Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Деструкторы экземпляра класса

Поиск

 

Деструкторы используются для уничтожения экземпляров классов.

 

  • В структурах определение деструкторов невозможно. Они применяются только в классах.
  • Класс может иметь только один деструктор.
  • Деструкторы не могут наследоваться или перегружаться.
  • Деструкторы невозможно вызвать. Они запускаются автоматически.
  • Деструктор не принимает модификаторы и не имеет параметров.

 

Например, следующая инструкция является объявлением деструктора класса Car:

 

class Car

{

~Car() // Деструктор

{

// Очистка...

}

}

 

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

 

protected override void Finalize()

{

try

{

// Очистка...

}

finally

{

base.Finalize();

}

}

 

Это означает, что метод Finalize вызывается рекурсивно для всех экземпляров цепочки наследования начиная с самого дальнего и заканчивая самым первым.

 

В следующем примере создаются три класса, образующих цепочку наследования. Класс First является базовым, класс Second является производным от класса First, а класс Third является производным от класса Second. Все три класса имеют деструкторы (не пустые, пустые дееструкторы лучше не применять из-за понижающейся при этом производительности). В методе Main() создаётся экземпляр самого дальнего в цепочке наследования класса. При выполнении программы обратим внимание, что происходит автоматический вызов деструкторов всех трёх классов по порядку от самого дальнего до первого в цепочке наследования:

 

class First

{

~First()

{

System.Diagnostics.Trace.WriteLine("Первый деструктор вызван.");

}

}

 

class Second: First

{

~Second()

{

System.Diagnostics.Trace.WriteLine("Второй деструктор вызван.");

}

}

 

class Third: Second

{

~Third()

{

System.Diagnostics.Trace.WriteLine("Третий деструктор вызван.");

}

}

 

class TestDestructors

{

static void Main()

{

Third t = new Third();

}

 

}

/* Выведет (в окно "Вывод" Visual Studio 2010):

* Первый деструктор вызван.

* Второй деструктор вызван.

* Третий деструктор вызван.

*/

 

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

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

В целом, язык C# не требует управления памятью в той степени, в какой это требуется в случае разработки кода на языке, не рассчитанном на среду выполнения со сборкой мусора. Это связано с тем, что сборщик мусора платформы.NET Framework неявным образом управляет выделением и высвобождением памяти для объектов. Однако при инкапсуляции приложением неуправляемых ресурсов, например окон, файлов и сетевых подключений, для высвобождения этих ресурсов следует использовать деструкторы. Если объект требует уничтожения, то сборщик мусора запускает выполнение метода Finalize этого объекта.

 

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

 

8. И ещё немного о классах и их использовании...

 

Допустим нужно создать программу для регистрации участников на олимпиаду по математике. Для нас не имеет значения, как выглядит человек, нам важно следующее: школа, класс, ФИО, год рождения, балл (это конечно упрощённая модель). Т. е. были выявлены общие характеристики для наших участников. Кроме того, нужно производить некоторые операции: регистрация участника, дисквалификация участника, начисление баллов и прочее. Участников у нас может быть очень много, но класс у нас будет всего один:

 

class participant

{

private string FIO;

private int school;

private int theclass;

private int point;

 

public participant() { }

 

public participant(string aFIO, int aSchool, int aClass, int aPoint)

{

this.FIO = aFIO;

this.school = aSchool;

this.theclass = aClass;

this.point = aPoint;

}

 

public void GetInfo()

{

Console.WriteLine("Ф.И.О.:" + this.FIO);

Console.WriteLine("Школа:" + this.school);

Console.WriteLine("Класc:" + this.theclass);

Console.WriteLine("Баллы:" + this.point);

}

}

 

Был создан класс, который называется participant (участник). Данный класс имеет 4 внутренние переменные: FIO, school, theclass и point. Третью переменную пришлось назвать theclass, а не class, потому что class является зарезервированным (ключевое слово же) и его нельзя использовать в качестве имени переменной.

Первый конструктор является конструктором по умолчанию, он собственно ничего не делает. Но в отличие от других языков программирования в C# нужно объявлять конструктор по умолчанию, т. к. автоматически он не создаётся. Второй конструктор принимает четыре параметра и присваивает их нашим внутренним переменным (инициализирует их). Конструктор называется точно так же как и класс, собственно это и делает его конструктором. Обратим внимание, на то, как происходит обращение к внутренним переменным: this.FIO.

this — это ссылка на текущий экземпляр класса. В процессе создания класса неизвестно, как будет называться объект, который этот класс реализует, поэтому его необходимо назвать this. Вообще, к членам и методам класса нужно обращаться через точку: «имя объекта».»имя члена».

Кроме этого у нашего класса есть один единственный метод: GetInfo, который отображает информацию о участнике.

 

Создаём экземпляр класса:

 

static void Main()

{

participant x = new participant("John A.", 10, 11, 100);

x.GetInfo();

}

 

Обратим вниманием, что невозможно изменить внутренние переменные объекта с помощью конструкции:

 

x.FIO = "Вася Пупкин";

 

Потому что, нет прав доступа к этой переменной (она объявлена как private).

Вложенные классы и понятие «Вложенные типы»

Вложенные классы и понятие «Вложенные типы»

 

Вложенные классы

 

Иногда некоторый клас с играет чисто вспомогательную роль для другого класса и используется только внутри него. В этом случае логично описать его внутри существующего класса. Вот пример такого описания:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace LC_Console

{

class ClassA

{

// Вложенный класс

private class ClassB

{

public int z;

}

// Переменная типа вложенного класса

private ClassB w;

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

public ClassA()

{

w = new ClassB();

w.z = 35;

}

// Некоторый метод

public int SomeMethod()

{

return w.z;

}

}

class Test

{

static void Main(string[] args)

{

ClassA v = new ClassA();

int k = v.SomeMethod();

Console.WriteLine(k);

// Выведет: 35

Console.WriteLine("Для продолжения нажмите любую клавишу...");;

Console.ReadKey();

}

}

}

 

Здесь класс ClassB объявлен внутри класса ClassA. Объявлен он со словом private, так что его экземпляры мы можем создавать только внутри класса ClassA (что и делаем в конструкторе класса ClassA). Методы класса ClassA имеют доступ к экземпляру класса ClassB (как, например, метод SomeMethod).

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

Обратим также внимание, как вложенные классы показываются на вкладке «Окно классов» в Среде разработки Visual Studio 2010:

 

Рис. 1. Окно классов проекта LC_Console

 

Понятие «Вложенные типы»

 

Итак, тип, определённый внутри класса или структуры, называется вложенным типом. Пример:

 

class Container

{

class Nested

{

Nested() { }

}

}

 

Независимо от того, являются ли внешние типы классом или структурой, вложенные типы по умолчанию являются private, но могут быть также public, protected internal, protected, internal. В предыдущем примере тип Nested недоступен для внешних типов, но он может являться открытым:

 

class Container

{

public class Nested

{

Nested() { }

}

}

 

Вложенный или внутренний тип может получить доступ к содержащему или внешнему типу. Чтобы получить доступ к содержащему типу, передаём его в качестве конструктора во вложенный тип. Пример:

 

public class Container

{

public class Nested

{

private Container parent;

 

public Nested()

{

}

 

public Nested(Container parent)

{

this.parent = parent;

}

}

}

 

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

В предыдущем объявлении полным именем класса Nested является Container.Nested. Это имя используется для создания нового экземпляра вложенного класса, как показано ниже:

 

Container.Nested nest = new Container.Nested();

 



Поделиться:


Последнее изменение этой страницы: 2016-08-15; просмотров: 414; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.133.148.76 (0.007 с.)