Konstruktory wystąpień (przewodnik programowania w języku C#)

Zadeklarujesz konstruktor wystąpienia, aby określić kod wykonywany podczas tworzenia nowego wystąpienia typu za pomocą new wyrażenia . Aby zainicjować klasę statyczną lub zmienne statyczne w klasie niestatycznej, można zdefiniować konstruktor statyczny.

Jak pokazano w poniższym przykładzie, można zadeklarować kilka konstruktorów wystąpień w jednym typie:

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)
    }
}

W poprzednim przykładzie pierwszy, bez parametrów, konstruktor wywołuje drugi konstruktor z obu argumentów równych 0. W tym celu użyj słowa kluczowego this .

Podczas deklarowania konstruktora wystąpienia w klasie pochodnej można wywołać konstruktor klasy bazowej. W tym celu użyj słowa kluczowego base , jak pokazano w poniższym przykładzie:

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
    }
}

Konstruktory bez parametrów

Jeśli klasa nie ma jawnych konstruktorów wystąpień, język C# udostępnia konstruktor bez parametrów, którego można użyć do utworzenia wystąpienia wystąpienia tej klasy, jak pokazano w poniższym przykładzie:

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
    }
}

Ten konstruktor inicjuje pola i właściwości wystąpienia zgodnie z odpowiednimi inicjatorami. Jeśli pole lub właściwość nie ma inicjatora, jego wartość jest ustawiona na wartość domyślną typu pola lub właściwości. Jeśli zadeklarowasz co najmniej jeden konstruktor wystąpienia w klasie, język C# nie udostępnia konstruktora bez parametrów.

Typ struktury zawsze zapewnia konstruktor bez parametrów. Konstruktor bez parametrów jest niejawnym konstruktorem bez parametrów, który generuje wartość domyślną typu lub jawnie zadeklarowany konstruktor bez parametrów. Aby uzyskać więcej informacji, zobacz sekcję Inicjowanie struktury i wartości domyślne w artykule Typy struktury.

Konstruktory podstawowe

Począwszy od języka C# 12, można zadeklarować podstawowy konstruktor w klasach i strukturach. Wszystkie parametry są umieszczane w nawiasach po nazwie typu:

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

Parametry konstruktora podstawowego znajdują się w zakresie w całej treści typu deklaratywnego. Mogą inicjować właściwości lub pola. Mogą być używane jako zmienne w metodach lub funkcjach lokalnych. Można je przekazać do konstruktora podstawowego.

Podstawowy konstruktor wskazuje, że te parametry są niezbędne dla dowolnego wystąpienia typu. Każdy jawnie napisany konstruktor musi używać this(...) składni inicjatora do wywoływania konstruktora podstawowego. Zapewnia to, że podstawowe parametry konstruktora są zdecydowanie przypisane przez wszystkie konstruktory. W przypadku dowolnego class typu, w tym record class typów, niejawny konstruktor bez parametrów nie jest emitowany, gdy podstawowy konstruktor jest obecny. W przypadku dowolnego struct typu, w tym record struct typów, niejawny konstruktor bez parametrów jest zawsze emitowany i zawsze inicjuje wszystkie pola, w tym podstawowe parametry konstruktora, do wzorca 0-bitowego. Jeśli napiszesz jawny konstruktor bez parametrów, musi wywołać konstruktor podstawowy. W takim przypadku można określić inną wartość dla podstawowych parametrów konstruktora. Poniższy kod przedstawia przykłady konstruktorów podstawowych.

// 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;
}

Atrybuty można dodać do syntetyzowanej podstawowej metody konstruktora, określając method: element docelowy atrybutu:

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

Jeśli nie określisz method elementu docelowego, atrybut zostanie umieszczony w klasie, a nie w metodzie.

W class typach i struct podstawowe parametry konstruktora są dostępne w dowolnym miejscu w treści typu. Mogą być używane jako pola składowe. Gdy jest używany podstawowy parametr konstruktora, kompilator przechwytuje parametr konstruktora w polu prywatnym z nazwą wygenerowaną przez kompilator. Jeśli podstawowy parametr konstruktora nie jest używany w treści typu, żadne pole prywatne nie jest przechwytywane. Ta reguła uniemożliwia przypadkowe przydzielanie dwóch kopii podstawowego parametru konstruktora przekazanego do konstruktora podstawowego.

Jeśli typ zawiera record modyfikator, kompilator zamiast tego syntetyzuje właściwość publiczną o takiej samej nazwie jak podstawowy parametr konstruktora. W przypadku record class typów, jeśli podstawowy parametr konstruktora używa tej samej nazwy co podstawowy konstruktor podstawowy, ta właściwość jest publiczną właściwością typu podstawowego record class . Nie jest ona duplikowana w typie pochodnym record class . Te właściwości nie są generowane dla typów innychrecord niż.

Zobacz też