Перейти к содержимому
Теория · Классы и объекты · урок 3 из 11

Конструкторы

В первом уроке темы дом строили пустым, а поля заполняли потом, отдельными строками. Стоит забыть одну строку, и в программе появляется дом без этажей:

C#
var a = new House();
a.Color = "red";
a.Floors = 2;
var b = new House();
b.Color = "blue";
Console.WriteLine(b.Color + ", " + b.Floors); // blue, 0

class House
{
    public string Color = "";
    public int Floors;
}

Строку b.Floors = 1; пропустили, и b.Floors осталось равным 0. Компилятор не возражает: для него ноль этажей — обычное число.

С настоящими домами так не бывает. Строителям сразу отдают бланк заказа: «красный дом, два этажа», и дом сдают уже готовым. Такой бланк заказа в C# — конструктор.

Что такое конструктор

Конструктор — особый метод класса, который выполняется при создании объекта через new. Он получает начальные значения и кладёт их в поля:

C#
var a = new House("red", 2);
Console.WriteLine(a.Color + ", " + a.Floors); // red, 2

class House
{
    public string Color;
    public int Floors;

    public House(string color, int floors)
    {
        Color = color;
        Floors = floors;
    }
}

Давайте разберём конструктор и его вызов:

  1. Его имя совпадает с именем класса: House.
  2. Типа результата у него нет, даже void: конструктор ничего не возвращает, он заполняет новый объект.
  3. new House("red", 2) создаёт объект и сразу вызывает конструктор с аргументами "red" и 2.
  4. Тело кладёт значения параметров в поля, и a получает дом, в котором уже всё заполнено.

Теперь этажи не забыть: вызов new House("red") без второго аргумента не скомпилируется. Строковому полю Color больше не нужно = "". Конструктор и так кладёт в него строку, поэтому предупреждения CS8618 нет.

Конструктор из одной инструкции, как и метод, можно записать через =>: public House(string color) => Color = color;.

Конструктор по умолчанию

В первом уроке темы у House не было конструктора, а new House() всё равно работал. Если в классе нет ни одного конструктора, компилятор добавляет конструктор по умолчанию: без параметров и с пустым телом. Поля тогда получают начальные значения из своих объявлений или значения по умолчанию.

Как только вы пишете свой конструктор, конструктор по умолчанию пропадает. Компилятор считает, что вы сами решили, как строить объект. Об этом часто спрашивают на собеседовании: «Когда у класса есть конструктор без параметров?» Ответ — когда в классе нет ни одного своего конструктора или когда конструктор без параметров объявлен явно.

Перегрузка конструкторов

Здесь бланк заказа и конструктор расходятся. У строительной фирмы бланк один, а конструкторов у класса может быть несколько, если у них разные списки параметров:

C#
var a = new House("red");
var b = new House("blue", 3);
Console.WriteLine(a.Floors + " " + b.Floors); // 1 3

class House
{
    public string Color;
    public int Floors;
    public House(string color) : this(color, 1) { }
    public House(string color, int floors)
    {
        Color = color;
        Floors = floors;
    }
}

Несколько методов с одним именем и разными параметрами называют перегрузкой. Компилятор выбирает нужный вариант по аргументам вызова:

  • new House("red") — один аргумент-строка, поэтому вызывается House(string color);
  • new House("blue", 3) — строка и число, поэтому вызывается House(string color, int floors).

Так перегружают и обычные методы класса. У Console.WriteLine 20 перегрузок: для int, для string, для bool и для других типов. Перегрузки должны отличаться числом или типами параметров. Два метода, которые отличаются только типом результата, не скомпилируются (CS0111).

Методы, объявленные среди инструкций верхнего уровня, перегружать нельзя. Второй метод с тем же именем там даёт ошибку CS0128, поэтому перегрузку показывают на методах класса.

Вызов через this(…)

Конструкция : this(color, 1) после параметров значит: сначала выполнить другой конструктор этого класса с такими аргументами. Короткий конструктор не повторяет присваивания, а передаёт работу полному и подставляет один этаж.

Разберём вызов new House("red"):

  1. Выбирается конструктор с одним параметром, и color равен "red".
  2. : this(color, 1) вызывает полный конструктор с аргументами "red" и 1.
  3. Полный конструктор заполняет Color и Floors.
  4. Выполняется тело короткого конструктора. Оно пустое: { }.

Если позже понадобится проверка этажей, её напишут в одном месте, в полном конструкторе.

Частая ошибка

Свой конструктор написали, а объект создают без аргументов, как раньше:

C#
var a = new House(); // ✗
Console.WriteLine(a.Floors);

class House
{
    public int Floors;

    public House(int floors)
    {
        Floors = floors;
    }
}
TEXT
error CS7036: There is no argument given that corresponds to the required parameter 'floors' of 'House.House(int)'

Программа не компилируется. Конструктора по умолчанию больше нет, а единственный конструктор требует аргумент floors. Передайте его: new House(2). Или объявите конструктор без параметров сами: public House() : this(1) { }.

Главное

  • Конструктор называется как класс, не имеет типа результата и выполняется при каждом new.
  • Если в классе нет своих конструкторов, компилятор добавляет конструктор по умолчанию; свой конструктор его убирает.
  • Перегрузка — несколько методов или конструкторов с одним именем и разными параметрами; вариант выбирается по аргументам.
  • : this(…) вызывает другой конструктор того же класса, чтобы не повторять код.