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

Как и в C++, классы C# обычно имеют конструктор по умолчанию без параметров, который просто вызывает конструктор без параметров непосредственного базового класса, а затем инициализирует все поля их параметрами по умолчанию. Так же как в C++, компилятор будет создавать этот конструктор по умолчанию, только если в коде явно не предоставлен никакой другой конструктор. Если какие-либо конструкторы присутствуют в определении класса, то в этом случае будут доступны только эти конструкторы, независимо от того, есть или нет среди них конструктор без параметров.

Как и в C++ можно обойтись без создания экземпляров класса, объявляя закрытый конструктор единственным.

class MyClass {

 private MyClass() {

 }

Это также не позволяет создавать экземпляры любых производных классов. Однако, если класс или методы в нем объявлены абстрактными, то нельзя создать экземпляр этого класса, причем не обязательно производного класса.

Списки инициализации конструктора

Конструкторы C# могут иметь элементы, которые выглядят как списки инициализации конструктора C++. Однако в C# такой список содержит только максимум один член и называется инициализатором конструктора. Элемент в инициализаторе должен быть либо конструктором непосредственного базового класса, либо другим конструктором того же класса. Синтаксис этих двух вариантов использует ключевые слова base и this соответственно:

class MyClass : MyBaseClass {

 MyClass(int X)

 : base(X) // выполняет конструктор MyBaseClass с одним параметром

 {

  // здесь другая инициализация

 }

 MyClass()

 : this(10) // выполняет конструктор MyClass с одним параметром,

            // передавая в него значение 10

 {

  // здесь другая инициализация

 }

Если явно не задан никакой список инициализации конструктора, то компилятор будет неявно использовать список из элемента base(). Другими словами, инициализатор по умолчанию вызывает конструктор по умолчанию базового класса. Это поведение совпадает с C++.

В отличие от C++ нельзя поместить переменные члены в список инициализации конструктора. Однако это только вопрос синтаксиса, так как эквивалент C# должен отметить свои начальные значения в определении класса.

Более серьезным различием является тот факт, что можно поместить только один иной конструктор в список. Это влияет на способ разработки конструкторов, хотя несомненно полезно, так как заставляет использовать хорошо определенную и эффективную парадигму организации конструкторов. Эта парадигма указана в приведенном выше коде. Все конструкторы следуют единому порядку, в котором выполняются различные конструкторы.

Деструкторы

C# реализует отличную от C++ модель программирования деструкторов. Это связано с тем, что механизм сборки мусора в C# предполагает следующее:

□ Существует меньшая необходимость в деструкторах, так как динамически распределенная память будет удаляться автоматически.

□ Так как невозможно предсказать, когда сборщик мусора реально разрушит заданный объект, то если для класса предоставляется деструктор, невозможно предсказать в точности, когда этот деструктор будет выполнен.

Поскольку память очищается в C# 'за сценой', то оказывается, что только небольшое число классов действительно нуждается в деструкторах. Для тех, кому это нужно (это классы, которые поддерживают внешние неуправляемые ресурсы, такие как соединения с файлами или с базами данных), C# имеет двухэтапный механизм разрушения:

1. Класс должен выводиться из интерфейса IDisposable и реализовывать метод Dispose(). Этот метод предназначен для явного вызова с помощью кода клиента для указания, что он закончил работать с объектом и требуется очистить ресурсы. (Интерфейсы будет рассмотрены позже в этом приложении.)

2. Класс должен отдельно реализовать деструктор, который рассматривается как запасной механизм, на случай, если клиент не вызывает Dispose().

Обычная реализация Dispose() выглядит следующим образом:

public void Dispose() {

 // очистка ресурсов

 System.GC.SuppressFinalize(this);

}

System.GC является базовым классом, представляющим сборщика мусора. SuppressFinalize() является методом, который информирует сборщика мусора, что нет необходимости вызывать деструктор для разрушаемого объекта. Вызов SuppressFinalize() важен, так как имеется снижение производительности, если в объекте есть деструктор, который нужно вызывать в то время, когда сборщик мусора выполняет свою работу. Следствием этого является то, что реальное освобождение управляемой памяти, занимаемой этим объектом, будет существенно задерживаться.

Синтаксис деструктора по сути такой же в C#, как и в C++. Отметим, что в C# не требуется объявлять деструктор виртуальным, компилятор будет это подразумевать. Не требуется также предоставлять модификатор доступа:

Class MyClass {

 ~MyClass() {

  // очистка ресурсов

 }

}

Хотя метод Dispose() обычно явно вызывается клиентами, C# допускает альтернативный синтаксис, который гарантирует, что компилятор примет меры, чтобы он был вызван. Если переменная объявлена внутри блока using(), то ее область действия совпадает с блоком using и ее метод Dispose() будет вызываться при выходе из блока:

using (MyClass MyObject = new MyClass()) {

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

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

Отметить Добавить цитату