// Сделать что-нибудь.

  Console.WriteLine("About to dispose.");

  // В этой точке переменная освобождается.

}

Далее добавьте к своим операторам верхнего уровня показанный ниже вызов:

Console.WriteLine("***** Fun with Dispose *****\n");

...

Console.WriteLine("Demonstrate using declarations");

UsingDeclaration();

Console.ReadLine();

Если вы изучите новый метод с помощью ildasm.exe, то (вполне ожидаемо) обнаружите тот же код, что и ранее:

.method private hidebysig static

  void  UsingDeclaration() cil managed

{

  ...

  .try

  {

  ...

  }  // end .try

  finally

  {

    IL_0018: callvirt instance void

      [System.Runtime]System.IDisposable::Dispose()

    ...

  }  // end handler

  IL_001f: ret

} // end of method Program::UsingDeclaration

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

<p id="AutBody_Root366">Создание финализируемых и освобождаемых типов</p>

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

Нетрудно догадаться, что в одном определении класса можно смешивать оба подхода, извлекая лучшее из обеих моделей. Если пользователь объекта не забыл вызвать метод Dispose(), тогда можно проинформировать сборщик мусора о пропуске процесса финализации, вызвав метод GC.SuppressFinalize(). Если же пользователь объекта забыл вызвать Dispose(), то объект со временем будет финализирован и получит шанс освободить внутренние ресурсы. Преимущество здесь в том, что внутренние неуправляемые ресурсы будут тем или иным способом освобождены.

Ниже представлена очередная версия класса MyResourceWrapper, который теперь является финализируемым и освобождаемым; она определена в проекте консольного приложения C# по имени FinalizableDisposableClass:

using System;

namespace FinalizableDisposableClass

{

  // Усовершенствованная оболочка для ресурсов.

  public class MyResourceWrapper : IDisposable

  {

    // Сборщик мусора будет вызывать этот метод, если

    // пользователь объекта забыл вызвать Dispose().

    ~MyResourceWrapper()

    {

     // Очистить любые внутренние неуправляемые ресурсы.

     // **Не** вызывать Dispose() на управляемых объектах.

    }

    // Пользователь объекта будет вызывать этот метод

    // для как можно более скорой очистки ресурсов.

    public void Dispose()

    {

      // Очистить неуправляемые ресурсы.

      // Вызвать Dispose() для других освобождаемых объектов,

      // содержащихся внутри.

      // Если пользователь вызвал Dispose(), то финализация

      // не нужна, поэтому подавить ее.

      GC.SuppressFinalize(this);

    }

  }

}

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

<p id="AutBody_Root367">Формализованный шаблон освобождения</p>
Перейти на страницу:

Похожие книги