Но ради интереса следует все же отметить, что оператор new разрешается использовать вместе с типами значений, как показывает следующий пример.

      Комментарии к записи Но ради интереса следует все же отметить, что оператор new разрешается использовать вместе с типами значений, как показывает следующий пример. отключены

int i = new int ();

При этом для типа int вызывается конструктор, инициализирующий по умолчанию переменную i нулевым значением. В качестве примера рассмотрим такую программу.

// Использовать оператор new вместе с типом значения.

Using System;

class newValue {

static void Main() {

int i = new int(); // инициализировать переменную i нулевым значением

Console.WriteLine(Значение переменной i равно:+ i);

}

}

Выполнение этой программы дает следующий результат.

Значение переменной i равно: О

Как показывает результат выполнения данной программы, переменная i инициализируется нулевым значением. Напомним, что если не применить оператор new, то переменная i окажется неинициализированной. Это может привести к ошибке при попытке воспользоваться ею в операторе, содержащем вызов метода WriteLine (), если предварительно не задать ее значение явным образом.

В общем, обращение к оператору new для любого типа значения приводит к вызову конструктора, используемого по умолчанию для данного типа. Но в этом случае память динамически не распределяется. Откровенно говоря, в программировании обычно не принято пользоваться оператором new вместе с типами значений.

“Сборка мусора” и применение деструкторов

Как было показано выше, при использовании оператора new свободная память для создаваемых объектов динамически распределяется из доступной буферной области оперативной памяти. Разумеется, оперативная память не бесконечна, и поэтому свободно доступная память рано или поздно исчерпывается. Это может привести к неудачному выполнению оператора new из-за нехватки свободной памяти для создания требуемого объекта. Именно по этой причине одной из главных функций любой схемы динамического распределения памяти является освобождение свободной памяти от неиспользуемых объектов, чтобы сделать ее доступной для последующего перераспределения. Во многих языках программирования освобождение распределенной ранее памяти осуществляется вручную. Например, в C++ для этой цели служит оператор delete. Но в C# применяется другой, более надежный подход: сборка мусора .

Система сборки мусора в C# освобождает память от лишних объектов автоматически, действуя незаметно и без всякого вмешательства со стороны программиста. Сборка мусора происходит следующим образом. Если ссылки на объект отсутствуют, то такой объект считается ненужным, и занимаемая им память в итоге освобождается и накапливается. Эта утилизированная память может быть затем распределена для других объектов.

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

Деструкторы

В языке C# имеется возможность определить метод, который будет вызываться непосредственно перед окончательным уничтожением объекта системой сборки мусора. Такой метод называется деструктором и может использоваться в ряде особых случаев, чтобы гарантировать четкое окончание срока действия объекта. Например, деструктор может быть использован для гарантированного освобождения системного ресурса, задействованного освобождаемым объектом. Следует, однако, сразу же подчеркнуть, что деструкторы — весьма специфические средства, применяемые только в редких, особых случаях. И, как правило, они не нужны. Но здесь они рассматриваются вкратце ради полноты представления о возможностях языка С#.

Ниже приведена общая форма деструктора:

~ имя_ кла сса () {

// код деструктора

}

где имя_класса означает имя конкретного класса. Следовательно, деструктор объявляется аналогично конструктору, за исключением того, что перед его именем указывается знак тильда (~). Обратите внимание на то, что у деструктора отсутствуют возвращаемый тип и передаваемые ему аргументы.

Для того чтобы добавить деструктор в класс, достаточно включить его в класс в качестве члена. Он вызывается всякий раз, когда предполагается утилизировать объект его класса. В деструкторе можно указать те действия, которые следует выполнить перед тем, как уничтожать объект.

Следует, однако, иметь в виду, что деструктор вызывается непосредственно перед сборкой мусора. Он не вызывается, например, в тот момент, когда переменная, содержащая ссылку на объект, оказывается за пределами области действия этого объекта. (В этом отношении деструкторы в C# отличаются от деструкторов в C++, где они вызываются в тот момент, когда объект оказывается за пределами области своего действия.) Это означает, что заранее нельзя знать, когда именно следует вызывать деструктор. Кроме того, программа может завершиться до того, как произойдет сборка мусора, а следовательно, деструктор может быть вообще не вызван.

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

// Продемонстрировать применение деструктора.

Using System;

class Destruct { public int x;

public Destruct(int i) {

х = i ;

}

// Вызывается при утилизации объекта.

-Destruct() -{

Console.WriteLine(Уничтожить+ х);

}

// Создает объект и тут же уничтожает его. public void Generator(int i) {

Destruct о = new Destruct (i);

}

}

class DestructDemo { static void Main() { int count;

Destruct ob = new Destruct(0);

/* А теперь создать большое число объектов.

В какой-то момент произойдет сборка мусора.

Примечание: для того чтобы активизировать сборку мусора, возможно, придется увеличить число создаваемых объектов. */

for(count=l; count100000; count++) ob.Generator(count);

Console.WriteLine(Готово!);

}

}

Эта программа работает следующим образом. Конструктор инициализирует переменную х известным значением. В данном примере переменная х служит в качестве идентификатора объекта. А деструктор выводит значение переменной х, когда объект утилизируется. Особый интерес вызывает метод Generator () , который создает и тут же уничтожает объект типа Destruct. Сначала в классе DestructDemo создается исходный объект ob типа Destruct, а затем осуществляется поочередное создание и уничтожение 100 тыс. объектов. В разные моменты этого процесса происходит сборка мусора. Насколько часто она происходит — зависит от нескольких факторов, в том числе от первоначального объема свободной памяти, типа используемой операционной системы и т.д. Тем не менее в какой-то момент начинают появляться сообщения, формируемые деструктором. Если же они не появятся до окончания программы, т.е. до того момента, когда будет выдано сообщение Готово!, попробуйте увеличить число создаваемых объектов, повысив предельное количество подсчитываемых шагов в цикле for.

И еще одно важное замечание: метод WriteLine () вызывается в деструкторе -Destruct () исключительно ради наглядности данного примера его использования. Как правило, деструктор должен воздействовать только на переменные экземпляра, определенные в его классе.

В силу того что порядок вызова деструкторов не определен точно, их не следует применять для выполнения действий, которые должны происходить в определенный момент выполнения программы. В то же время имеется возможность запрашивать сборку мусора, как будет показано в части II этой книги при рассмотрении библиотеки классов С#. Тем не менее инициализация сборки мусора вручную в большинстве случаев не рекомендуется, поскольку это может привести к снижению эффективности программы. Кроме того, у системы сборки мусора имеются свои особенности — даже если запросить сборку мусора явным образом, все равно нельзя заранее знать, когда именно будет утилизирован конкретный объект.

Ключевое слово this

Прежде чем завершать эту главу^ необходимо представить ключевое слово this. Когда метод вызывается, ему автоматически передается ссылка на вызывающий объект, т.е. тот объект, для которого вызывается данный метод. Эта ссылка обозначается ключевым словом this. Следовательно, ключевое слово this обозначает именно тот объект, по ссылке на который действует вызываемый метод. Для того чтобы стало яснее назначение ключевого слова this, рассмотрим сначала пример программы, в которой создается класс Rect, инкапсулирующий ширину и высоту прямоугольника и включающий в себя метод Area () , возвращающий площадь прямоугольника.

Using System;

class Rect {

Личный Интерес / Personal Interest. Фильм. StarMedia. Детективная Мелодрама. 2015