Конструкторы экземпляров (руководство по программированию на C#)

Конструктор экземпляра объявляется для указания кода, выполняемого при создании нового экземпляра типа с помощью выражения new. Чтобы инициализировать статический класс или статические переменные в нестатическом классе, можно определить статический конструктор.

Как показано в следующем примере, можно объявить несколько конструкторов экземпляров в одном типе:

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. Для этого воспользуйтесь ключевым словом 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
    }
}

Этот конструктор инициализирует поля и свойства экземпляров в соответствии с необходимыми инициализаторами. Если поле или свойство не имеет инициализатора, его значение устанавливается в значение по умолчанию для типа поля или свойства. Если в классе объявлен хотя бы один конструктор экземпляра, 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 типах основные параметры конструктора доступны в любом месте текста типа. Их можно использовать в качестве полей-членов. При использовании основного параметра конструктора компилятор фиксирует параметр конструктора в частном поле с именем, созданным компилятором. Если основной параметр конструктора не используется в тексте типа, частное поле не фиксируется. Это правило предотвращает случайное выделение двух копий основного параметра конструктора, передаваемого базовому конструктору.

Если тип включает record модификатор, компилятор вместо этого синтезирует общедоступное свойство с тем же именем, что и основной параметр конструктора. Если record class для типов основной параметр конструктора использует то же имя, что и базовый конструктор, это свойство является общедоступным свойством базового record class типа. Он не дублируется в производном record class типе. Эти свойства не создаются для нетиповrecord .

См. также