C#: Конструкторы

Конструктор - это особый тип метода, который можно вызвать неявным способом и никогда явно. Конструктор автоматически вызывается, когда мы выделяем память при помощи ключевого слова newМы можем перегрузить конструктор, создав несколько определений, которые отличаются по своим параметрам.
Каждый класс (и структура) имеет хотя бы один конструктор. Если мы создали конструктор явно, то компилятор помещает стандартный конструктор (без параметров, с пустым телом). Как только мы определяем один конструктор, компилятор не вставляет конструктор по умолчанию.
Сигнатура конструктора является специальной. Она не имеет типа возврата, так как конструктор неявно возвращает новый экземпляр, т.е. экземпляр класса. Также конструктор определяется его именем, которое является тем же именем, что и класс. Давайте посмотрим на некоторые конструкторы:

class MyClass
{
public MyClass()
{
//Empty default constructor
}

public MyClass(int a)
{
//Constructor with one argument
}

public MyClass(int a, string b)
{
//Constructor with two arguments
}

public MyClass(int a, int b)
{
//Another constructor with two arguments
}
}

Это выглядит довольно прямолинейно. Короче говоря, конструктор - это метод с именем класса, в котором не указывается никакого возвращаемого значения значения. Использование различных конструкторов возможно при создании экземпляра объекта класса.

MyClass a = new MyClass();
MyClass b = new MyClass(2);
MyClass c = new MyClass(2, "a");
MyClass d = new MyClass(2, 3);

Конечно, может быть, что один конструктор должен будет выполнять ту же работу, что и другой конструктор. В этом случае кажется, что у нас есть только два варианта:
  1. Скопируйте и вставьте содержимое.
  2. Извлечение содержимого в метод, который затем вызывается обоими конструкторами.
Во-первых, это простой подход без принципа DRY (Do not Repeat Yourself). Второй вариант, возможно, также не очень хорош, так как это может привести к злоупотреблению методом в других местах. Поэтому C # вводит понятие цепочки конструкторов. Прежде чем мы на самом деле выполняем инструкции из одного конструктора, мы вызываем другой конструктор. Синтаксис зависит от двоеточия :и указателя экземпляра текущего класса this:

class MyClass
{
public MyClass()
: this(1, 1) //This calls the constructor with 2 arguments
{
}

public MyClass(int a, int b)
{
//Do something with a and b
}
}

Здесь конструктор по умолчанию использует конструктор с двумя параметрами для выполнения некоторых операций инициализации. Работа по инициализации является наиболее популярным вариантом использования конструктора. Конструктор должен быть легким методом, который выполняет некоторую инициализацию предварительной обработки / установки / переменной.
Оператор двоеточия для цепочки конструкторов используется по определенной причине. Как и с наследованием, каждый конструктор должен вызвать другой конструктор. Если вызов не указан (т. е. нет никакого предыдущего конструктора), то вызываемый конструктор является конструктором по умолчанию базового класса. Поэтому второй конструктор в предыдущем примере в действительности выглядит следующим образом:

public MyClass(int a, int b)
: base()
{
//Do something with a and b
}

Однако дополнительная строка избыточна, поскольку компилятор автоматически вставляет ее. Есть только два случая, когда мы должны указать базовый конструктор для цепочки конструкторов:
  1. Когда мы действительно хотим вызвать другой базовый конструктор, вместо конструктора по умолчанию базового класса.
  2. Когда нет конструктора по умолчанию базового класса.
Причина построения цепочки конструктора с конструктором базового класса проиллюстрирована на следующем рисунке.

Принцип построения цепочки

Мы видим , что в этой иерархии классов для создания экземпляра Porsche, экземпляр Car должен быть создан. Однако для этого создания требуется создание экземпляра Vehicle, для которого требуется создание экземпляра ObjectКаждое инстанцирование связано с вызовом конструктора, который должен быть указан. Компилятор C # будет автоматически вызывать пустой конструктор, но это возможно только в том случае, если такой конструктор существует. В противном случае мы должны четко указать компилятору, что вызывать.
Существуют также случаи, когда другие модификаторы доступа для конструктора могут иметь смысл. Если мы хотим предотвратить создание экземпляра определенного типа (например, с abstract), мы могли бы создать один конструктор по умолчанию и сделать его protectedС другой стороны, это простой так называемый шаблон Singleton :



class MyClass


{


private static MyClass instance;


private MyClass() { }


public static MyClass Instance


{


get


{


if (instance == null)


instance = new MyClass();


return instance;


}


}


}



Теперь мы не можем создавать экземпляры класса, но мы можем получить доступ к статическому свойству Instanceс помощью MyClass.InstanceЭто свойство не только имеет доступ к статической переменной instance, но также имеет доступ ко всем private членам, таким как конструктор. Следовательно, он может создать экземпляр и вернуть созданный экземпляр.
Эта реализация имеет два основных преимущества:
  • Поскольку экземпляр создается внутри Instance метода свойств, класс может выполнять дополнительные функции (например, создавать экземпляр подкласса), даже если он может вводить нежелательные зависимости.
  • Создание экземпляра не выполняется до тех пор, пока объект не запросит экземпляр. Этот подход называется ленивой инициализацией.

Комментарии

Популярные сообщения из этого блога

Аппроксимация функций рядом Тейлора

Doxygen, оформление документации

Основные структуры данных: Множества