インスタンス コンストラクター (C# プログラミング ガイド)

インスタンス コンストラクターを宣言して、newを使用して型の新しいインスタンスを作成するときに実行されるコードを指定します。 static クラスを初期化する場合、または非静的クラス内の静的変数を初期化する場合は、static コンストラクターを定義します。

次の例に示すように、1 つの型で複数のインスタンス コンストラクターを宣言できます。

class Coords
{
    public Coords()
        : this(0, 0)
    {  }

    public Coords(int x, int y)
    {
        X = x;
        Y = y;
    }

    public int X { get; set; }
    public int Y { get; set; }

    public override string ToString() => $"({X},{Y})";
}

class Example
{
    static void Main()
    {
        var p1 = new Coords();
        Console.WriteLine($"Coords #1 at {p1}");
        // Output: Coords #1 at (0,0)

        var p2 = new Coords(5, 3);
        Console.WriteLine($"Coords #2 at {p2}");
        // Output: Coords #2 at (5,3)
    }
}

前の例では、最初のパラメーターなしのコンストラクターにより、両方の引数が 0 と等しい 2 番目のコンストラクターが呼び出されます。 これを行うには、this キーワードを使用します。

派生クラスでインスタンス コンストラクターを宣言する場合は、基底クラスのコンストラクターを呼び出すことができます。 これを行うには、次の例に示すように、base キーワードを使用します。

abstract class Shape
{
    public const double pi = Math.PI;
    protected double x, y;

    public Shape(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    public abstract double Area();
}

class Circle : Shape
{
    public Circle(double radius)
        : base(radius, 0)
    {  }

    public override double Area() => pi * x * x;
}

class Cylinder : Circle
{
    public Cylinder(double radius, double height)
        : base(radius)
    {
        y = height;
    }

    public override double Area() => (2 * base.Area()) + (2 * pi * x * y);
}

class Example
{
    static void Main()
    {
        double radius = 2.5;
        double height = 3.0;

        var ring = new Circle(radius);
        Console.WriteLine($"Area of the circle = {ring.Area():F2}");
        // Output: Area of the circle = 19.63
        
        var tube = new Cylinder(radius, height);
        Console.WriteLine($"Area of the cylinder = {tube.Area():F2}");
        // Output: Area of the cylinder = 86.39
    }
}

パラメーターなしのコンストラクター

"クラス" に明示的なインスタンス コンストラクターがない場合、C# には、次の例に示すように、そのクラスのインスタンスをインスタンス化するために使用できるパラメーターなしのコンストラクターが用意されています。

public class Person
{
    public int age;
    public string name = "unknown";
}

class Example
{
    static void Main()
    {
        var person = new Person();
        Console.WriteLine($"Name: {person.name}, Age: {person.age}");
        // Output:  Name: unknown, Age: 0
    }
}

そのコンストラクターにより、対応する初期化子に従ってインスタンス フィールドとプロパティが初期化されます。 フィールドまたはプロパティに初期化子がない場合、その値はフィールドまたはプロパティの型の既定値に設定されます。 クラス内で少なくとも 1 つのインスタンス コンストラクターを宣言する場合、C# によってパラメーターなしのコンストラクターは提供されません。

"構造体" 型では常に、パラメーターなしのコンストラクターが提供されます。 パラメーターなしのコンストラクターは、型の既定値を生成する暗黙的なパラメーターなしのコンストラクターか、明示的に宣言されたパラメーターなしのコンストラクターです。 詳細については、「構造体型」の記事の構造体の初期化と既定値に関するセクションを参照してください。

プライマリ コンストラクター

C#12 以降、クラスと構造体で "プライマリ コンストラクター" を宣言できるようになりました。 パラメーターは型名の後のかっこ内に記述します。

public class NamedItem(string name)
{
    public string Name => name;
}

プライマリ コンストラクターのパラメーターは、宣言する型の本文全体のスコープ内にあります。 これらを使って、プロパティまたはフィールドを初期化できます。 これらを使って、メソッドまたはローカル関数の変数として使用できます。 これらを基本コンストラクターに渡すことができます。

プライマリ コンストラクターは、これらのパラメータがこの型のどのインスタンスにも必要であることを示しています。 明示的に記述されたコンストラクターは、this(...) 初期化子構文を使ってプライマリ コンストラクターを呼び出す必要があります。 これにより、プライマリ コンストラクター パラメーターは、すべてのコンストラクターによって確実に割り当てられるようになります。 すべての class 型 (record class 型など) では、プライマリ コンストラクターが存在する場合、暗黙的なパラメーターなしコンストラクターは生成されません。 すべての struct 型 (record struct 型など) では、暗黙的なパラメーターなしのコンストラクターが常に生成され、プライマリ コンストラクターのパラメーターを含むすべてのフィールドは常に 0 ビット パターンに初期化されます。 明示的なパラメーターなしのコンストラクターを記述する場合は、プライマリ コンストラクターを呼び出す必要があります。 その場合、プライマリ コンストラクター パラメーターに別の値を指定できます。 次のコードは、プライマリ コンストラクターの例を示しています。

// name isn't captured in Widget.
// width, height, and depth are captured as private fields
public class Widget(string name, int width, int height, int depth) : NamedItem(name)
{
    public Widget() : this("N/A", 1,1,1) {} // unnamed unit cube

    public int WidthInCM => width;
    public int HeightInCM => height;
    public int DepthInCM => depth;

    public int Volume => width * height * depth;
}

属性で method: ターゲットを指定することで、合成されたプライマリ コンストラクター メソッドに属性を追加できます。

[method: MyAttribute]
public class TaggedWidget(string name)
{
   // details elided
}

method ターゲットを指定しない場合、属性はメソッドではなくクラスに配置されます。

class 型と struct 型では、プライマリ コンストラクター パラメーターは型の本文内のどこでも使用できます。 メンバー フィールドとして使うこともできます。 プライマリ コンストラクター パラメーターを使う場合、コンパイラは、コンパイラによって名前が生成されたプライベート フィールドにコンストラクター パラメーターを取り込みます。 型の本文にプライマリ コンストラクター パラメーターが使われていない場合、プライベート フィールドは取り込まれません。 この規則により、基本コンストラクターに渡されるプライマリ コンストラクター パラメーターのコピーを誤って 2 つ割り当てることを防ぐことができます。

型に record 修飾子が含まれている場合、コンパイラは代わりにプライマリ コンストラクター パラメーターと同じ名前のパブリック プロパティを合成します。 record class 型の場合、プライマリ コンストラクター パラメーターが基本プライマリ コンストラクターと同じ名前を使っていると、そのプロパティは基本 record class 型のパブリック プロパティになります。 派生 record class 型では複製されません。 record 型以外では、これらのプロパティは生成されません。

関連項目