C# ユーザー定義型データの深掘り「構造体」


おはようございますこんにちはこんばんは
ユーザー定義型データということで、この記事の続きです。

おさらい

ユーザー定義型データにはこんな種類がありました。

データ型 型の種類
構造体 値型
列挙体 値型
リスト 参照型
レコード 参照型
配列 参照型
クラス 参照型
デリゲート 参照型
インターフェイス 参照型

さらにメモリ、値型、参照型についてお話しした記事もありましたね。
この記事は関係のないこと(PCの主要パーツ)にもちらっと触れているので、興味があればご覧ください。

ユーザー定義型データをそれぞれ見ていこう

多いなぁ長くなりそう笑
できればパパッといきたいですね!
ということで早速上から順に見ていきましょうか!
長期連載になる可能性…

構造体

構造体はクラスとよく似た機能を持っている値型のデータです。

構造体の例
using System;

var point = new Point(10, 40); //魔法のキーワードを使ってPoint構造体のインスタンスをx = 10, y = 40で生成
point.Main(); //出力は「X = 10, Y = 40」

//構造体の定義↓
public readonly struct Point //読み取り専用のPoint構造体を定義する
{
    public Point(int x, int y) 
    {
        X = x; //Pointメソッドのint型変数xの値をXフィールドに格納する
        Y = y; //Pointメソッドのint型変数yの値をYフィールドに格納する
    }

    public int X { get; } // Xは読み取り専用ですよ(この時点では変数)
    public int Y { get; } // Yは読み取り専用ですよ(この時点では変数)

    public void Main() //コンソールに表示するだけのメソッド
    {
        Console.WriteLine("X = {0}, Y = {1}", X, Y); 
    }
}

これ合ってるかなぁって感じで書きました。(コメントアウトの内容も心配です〜)
レシピ本見て改変しています。
ちなみにレシピ本にはMainメソッドはなく、overrideしたToStringメソッドで値を返し、Console.WriteLine(point.ToString())で値を出力しています。
何言ってるんだって感じですよね。とりあえず頭の中に入力された情報を何かしらの形で出力することが目的なので、コードを改変してますよということです。
なんてったって備忘録ですから。(しかもレシピ本はバージョンがちょっと古いやつね)
一応コンソールアプリで実行してみてエラーはなかったので、出力自体は可能です。

ところで構造体の定義でMainメソッドがあって良いものなのかという疑問があるのですがどうなんでしょ?

構造体の定義に必要なこと

structキーワード

structのMS公式ドキュメント
構造体を作りますよという宣言です。structure(構造)のことですね。

newキーワード

newのMS公式ドキュメント
構造体を定義した上に変数を宣言、newキーワードでインスタンスを生成します。
以前書いた記事でもご紹介してますね。

なるべく読み取り専用で!

でもネット記事によってはそこまで重要ではなさそうな印象なので、意外と必要ではないかも?

必須ではないが新しく出たキーワード

public

publicのMS公式ドキュメント
割と必須かもしれないと思いつつこちらに書いています。(もしかしたら以前書いた記事で出てきているかも?)
今回はpublicキーワードやprivateキーワードなどがメインの記事ではないので。
このキーワードはアクセス修飾子というものになります。
これはプログラムないだろうが別のソースファイルだろうが同一プロジェクト内であればこの変数やメソッドにアクセスできますよという、スコープ範囲を明示するものです。(僕の解釈です。)
一応スコープ範囲について補足すると、「あなた(変数やメソッド)の適用範囲はここからここまでね、これ以上超えたら使えないよ」みたいな感じ。
スコープについては別記事で詳しく解説します。

readonly

readonlyのMS公式ドキュメント
読み取り専用であることを明示するキーワードです。
構造体の定義の際はできるだけreadonlyキーワードを使用することが推奨されています。(レシピ本が言ってた)

get

getのMS公式ドキュメント
アクセサーと呼ばれるキーワードです。
getなので、値を受け取りますよという意味です。
今回のコードではreadonlyキーワードを使っているため、フィールドの値は読み取り専用である必要があります。
反対にreadonlyを使っていない場合は、getキーワードの他にsetキーワードというものも使えます。
setキーワードはgetキーワードの逆で、値を書き込みますよみたいな感じです。(若干違いますがわかりやすくするためですご了承を)
getキーワード、setキーワード共にさまざまな書き方があるので、いずれアクセサーについても投稿しますね。

構造体でできないこと

以前の記事でクラスについて少し触れましたが、なんとなく似ている気がしますよね。
冒頭でもクラスとよく似た〜なんて言っているので実際似ているんです。
そんなクラスと構造体の違いなのですが、クラスと違ってできないことがあります。

  • クラスの継承ができない(そもそもクラスではないし、継承元にはなれない)
  • インスタンスフィールドの初期化ができない
  • インスタンスプロパティの初期化ができない
  • 引数なしコンストラクターの定義ができない(引数ありコンストラクタは可能で、クラスは引数の有無に関わらず可能)
  • 静的なクラス/構造体の生成ができない

長期連載確定ですね

ソースコード載せてさらにキーワードの解説となると、やっぱりちょっと長くなりますね。
読みやすいように一つ一つ解説する感じにしてみましょう。(何度も言いますが備忘録です)

という訳で今回はここまで!
お疲れ様でした!