xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

パラメーターなし構造体コンストラクタ

C# 5.0 までは構造体 (struct) はパラメーターのないコンストラクタを作ることができませんでした (IL の制約ではなく C# の言語仕様としての制約)。これが結構「ぐぬぬ...」なときがありましたが、C# 6.0 では晴れてこの制限が解放されました。

struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
    public Point()  //--- C# 6.0 で書けるようになった
    {
        this.X = 1;
        this.Y = 2;
    }
}

これにより、任意の初期値を与えたフィールド/プロパティの初期化ができるようになります。

コンストラクタ呼び出しのルール

先のパラメーターなしコンストラクタですが、明示的なコンストラクタ呼び出し (new T();) をした場合にのみ実行されます。以下は簡単に実験してみた結果です。

struct Complex
{
    public double Real { get; set; }
    public double Imaginary { get; set; }

    public Complex()
    {
        Console.WriteLine("パラメーターなしコンストラクタが呼び出されました");
        this.Real = 1;
        this.Imaginary = 2;
    }

    public override string ToString()
    {
        return $"({this.Real}, {this.Imaginary})";
    }
}
static void Main()
{
    Console.WriteLine("---------- 1");
    var c1 = new Complex();
    Console.WriteLine(c1);

    Console.WriteLine("---------- 2");
    var c2 = default(Complex);
    Console.WriteLine(c2);

    Console.WriteLine("---------- 3");
    var c3 = new Complex[1].First();
    Console.WriteLine(c3);
}

/*
---------- 1
パラメーターなしコンストラクタが呼び出されました
(1, 2)
---------- 2
(0, 0)
---------- 3
(0, 0)
*/

default(T) や配列の要素としての既定値インスタンス生成では呼び出されないことが分かります。これらはこれまで通り単なるゼロ初期化となります。このルールはしっかり押さえておかないと不意のバグになるかもなので注意が必要です。

2015/03/07 : 追記

最適化に関する回避不能な問題が発見されたため、搭載が見送られました。RC (リリース候補版) になってからの取り下げということで、残念です。