Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ПИ Программирование на С# _Хотов.docx
Скачиваний:
4
Добавлен:
01.07.2025
Размер:
2.22 Mб
Скачать
        1. Комбинирование подходов

Мы рассмотрели два подхода. Какой же из них лучше? С одной стороны, метод Dispose позволяет в любой момент времени вызвать освобождение связанных ресурсов, а с другой - программист, использующий наш класс, может забыть поставить в коде вызов метода Dispose. В общем бывают различные ситуации. И чтобы сочетать плюсы обоих подходов мы можем использовать комбинированный подход. Microsoft предлагает нам использовать следующий формализованный шаблон:

public class SomeClass: IDisposable

{

private bool disposed = false;

// реализация интерфейса IDisposable.

public void Dispose()

{

Dispose(true);

// подавляем финализацию

GC.SuppressFinalize(this);

}

protected virtual void Dispose(bool disposing)

{

if (!disposed)

{

if (disposing)

{

// Освобождаем управляемые ресурсы

}

// освобождаем неуправляемые объекты

disposed = true;

}

}

// Деструктор

~SomeClass()

{

Dispose (false);

}

}

Логика очистки реализуется перегруженной версией метода Dispose(bool disposing). При вызове деструктора в качестве параметра disposing передается значение false, чтобы избежать очистки управляемых ресурсов, так как мы не можем быть уверенными в их состоянии, что они до сих пор находятся в памяти. И в этом случае остается полагаться на деструкторы этих ресурсов. Ну и в обоих случаях освобождаются неуправляемые ресурсы.

Еще один важный момент - вызов в методе Dispose метода GC.SuppressFinalize(this). GC.SuppressFinalize не позволяет системе выполнить вызвать метод Finalize для данного объекта.

Таким образом, даже если разработчик не использует в программе метод Dispose, все равно произойдет очистка и освобождение ресурсов.

          1. Общие рекомендации по использованию Finalize и Dispose

  • Деструктор следует реализовывать только у тех объектов, которым он действительно необходим, так как метод Finalize оказывает сильное влияние на производительность

  • После вызова метода Dispose необходимо блокировать у объекта вызов метода Finalize с помощью GC.SuppressFinalize

  • При создании производных классов от базовых, которые реализуют интерфейс IDisposable, следует также вызывать метод Dispose базового класса:

  • public class Derived: Base

  • {

  • private bool IsDisposed = false;

  • protected override void Dispose(bool disposing)

  • {

  • if (!IsDisposed)

  • {

  • if (disposing)

  • {

  • // Освобождение управляемых ресурсов

  • }

  • IsDisposed = true;

  • }

  • // Обращение к методу Dispose базового класса

  • base.Dispose(disposing);

  • }

  • }

  • Отдавайте предпочтение комбинированному шаблону, реализующему как метод Dispose, так и деструктор

      1. Указатели

Если вы программировали на С/С++, то, возможно, вы знакомы с таким понятием как указатели. Указатели позволяют получить доступ к определенной ячейке памяти и произвести определенные манипуляции со значением, хранящимся в этой ячейке.

В языке C# указатели очень редко используются, однако в некоторых случаях можно прибегать к ним для оптимизации приложений. Код, применяющий указатели, еще называют небезопасным кодом. Однако это не значит, что он представляет какую-то опасность. Просто при работе с ним все действия по использованию памяти, в том числе по ее очистке, ложится целиком на нас, а не на среду CLR. И с точки зрения CLR такой код не безопасен, так как среда не может проверить данный код, поэтому повышается вероятность различного рода ошибок.

Чтобы использовать небезопасный код в C#, надо первым делом указать проекту, что он будет работать с небезопасным кодом. Для этого надо установить в настройках проекта соответствующий флаг - в меню Project (Проект) найти Свойства проекта. Затем в меню Build установить флажок Allow unsafe code (Разрешить небезопасный код):

Теперь мы можем приступать к работе с небезопасным кодом и указателями.