この章のテーマ §
structキーワード(構造体)について学びます。これは値型を自分で作るために使用するキーワードです。
前提知識 §
Console.WriteLineメソッド, 値型と参照型, 文字列の基礎, 変数の基礎, int型, class,プロパティ, コンストラクタ, 型のデフォルト値, with 式
解説 §
classキーワードで自作できる型は、全て参照型です。しかし、C#には参照型の他に値型もあったはずです。値型は実作できないのでしょいか? できます。そのためには、classキーワードの代わりにstructキーワードを使用するだけです。これを構造体と呼びます。構造体も、プロパティやメソッドを含めることができ、クラスと同じように扱うことができます。
しかし、一部に異なる振る舞いや制約が付くことがあり、classとstructは完全に互換ではありません。
特に大きな相違点は、【構造体はコンストラクタが実行されないケースがある】という点です。サンプルソースにはコンストラクタが実行されないケースと実行されるケースが紹介されています。
一般的にnew演算子を経由しないで確保された構造体はコストラクタが走りません。たとえば、サンプルソースの例だと、配列を確保するためのnew演算子は存在しますが、配列のメンバーを確保するためのnew演算子は存在しません。その場合は全てのメンバーがそのメンバーの型のデフォルト値で初期化されます。ここでは、public int X { get; set; } = 1;のようなプロパティの初期化も実行されていないことに注意して下さい。コンストラクタが実行されないとき、全ての明示的な初期化も実行されません。
罠の数々 §
- structキーワードを使う機会は多くない。しかし、クラスライブラリの基本的な型(intやDatreTime)が構造体なので、利用する機会は多い
- 大量の小さなオブジェクトを作成するプログラムは、構造体を使うと速度を改善できる可能性がある。覚えておこう
- 構造体は、値型なのでnull値になれない。nullを使うためにnull許容型にすると参照型になってしまい、値型としての特性が一部失われる。nullは使えないと割り切って、特定の値を無効扱いにして対処することもある
- 構造体にreadonlyキーワードを付けると読み取り専用にできる。全てのフィールドはreadonly、全てのプロパティは読み出し専用であること
- with 式で値を変更することができる。これを用いると読み出し専用でも値を変更できる
- 構造体のnew演算子は、新しいメモリを確保しない。確保済みのメモリに対して初期化を行うだけである
参考リンク §
構造体型 (C# リファレンス)
サンプルソース: kw_struct §
Console.WriteLine("コンストラクタが実行されるとき");
MyStruct a = new MyStruct(1);
Console.WriteLine(a.X);
Console.WriteLine("コンストラクタが実行されないとき");
MyStruct[] b = new MyStruct[1];
Console.WriteLine(b[0].X);
public struct MyStruct
{
public int X { get; set; } = 1;
public MyStruct()
{
Console.WriteLine("コンストラクタが実行されました。");
}
public MyStruct(int n)
{
Console.WriteLine("引数のあるコンストラクタが実行されました。");
Console.WriteLine($"メンバーXを{n}にします。");
X = n;
}
}
実行結果 §
コンストラクタが実行されるとき
引数のあるコンストラクタが実行されました。
メンバーXを1にします。
1
コンストラクタが実行されないとき
0
リポジトリ §
https://github.com/autumn009/CSharpPrimer2
練習問題 §
以下のプログラムの実行結果は"2030/01/01 12:30:00"になる。
var d1 = new DateTime(2030,1,1,12,30,0);
Console.WriteLine(d1);
では以下のプログラムの実行結果を予測してみよう。
var d2 = new DateTime();
Console.WriteLine(d2);
- 現在の日付時刻になる
- 0000/00/00 0:00:00
- 0001/01/01 0:00:00
- 0001/01/01 1:01:01
- 1970/01/01 0:00:00
[[解答]]