Поделиться через


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

// 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.

См. также