Читаем Язык программирования С# 2005 и платформа .NET 2.0. полностью

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

static void Main(string[] args) {

 MyResourceWrapper rw = new MyResourceWrapper();

 try {

  // Использование членов rw.

 } finally {

  // Dispose () вызывается всегда, есть ошибки или нет.

  rw.Dispose();

 }

}

Этот пример применения технологии "Безопасного программирования" прекрасен, но реальность такова, что лишь немногие разработчики готовы мириться с перспективой помещения каждого типа, предполагающего освобождение ресурсов, в рамки блока try/catch/finally только для того, чтобы гарантировать вызов метода Dispose(). Поэтому для достижения того же результата в C# предусмотрен намного более удобный синтаксис, реализуемый с помощью ключевого слова using.

static void Main(string[] args) {

 // Dispose() вызывается автоматически при выходе за пределы

 // области видимости using.

 using(MyResourceWrapper rw = new MyResourceWrapper()) {

  // Использование объекта rw.

 }

}

Если с помощью ildasm.exe взглянуть на CIL-код метода Main(), то вы обнаружите, что синтаксис using на самом деле разворачивается в логику try/finally с ожидаемым вызовом Dispose().

.method private hidebysig static void Main(string [] args) cil managed {

 …

 .try {

  …

 } // end try

 finally {

  …

  IL_0012: callvirt instance void SimpleFinalize.MyResourceWrapper::Dispose()

 } // end handler

} // end of method Program::Main

Замечание. При попытке применить using к объекту, не реализующему интерфейс IDisposable, вы получите ошибку компиляции.

Этот синтаксис исключает необходимость применения "ручной укладки" объектов в рамки программной логики try/finally, но, к сожалению, ключевое слово using в C# является двусмысленным (оно используется для указания пространств имен и для вызова метода Dispose()). Тем не менее, для типов .NET, предлагающих интерфейс IDisposable, синтаксическая конструкция using гарантирует автоматический вызов метода Dispose() при выходе из соответствующего блока.

Исходный код. Проект SimpleDispose размещен в подкаталоге, соответствующем главе 5.

<p>Создание типов, предусматривающих освобождение ресурсов и финализацию</p>

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

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

// Сложный контейнер ресурсов.

public class MyResourceWrapper: IDisposable {

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

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

 ~MyResourceWrapper() {

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

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

 }

Перейти на страницу:

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

97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

Успешная карьера архитектора программного обеспечения требует хорошего владения как технической, так и деловой сторонами вопросов, связанных с проектированием архитектуры. В этой необычной книге ведущие архитекторы ПО со всего света обсуждают важные принципы разработки, выходящие далеко за пределы чисто технических вопросов.?Архитектор ПО выполняет роль посредника между командой разработчиков и бизнес-руководством компании, поэтому чтобы добиться успеха в этой профессии, необходимо не только овладеть различными технологиями, но и обеспечить работу над проектом в соответствии с бизнес-целями. В книге более 50 архитекторов рассказывают о том, что считают самым важным в своей работе, дают советы, как организовать общение с другими участниками проекта, как снизить сложность архитектуры, как оказывать поддержку разработчикам. Они щедро делятся множеством полезных идей и приемов, которые вынесли из своего многолетнего опыта. Авторы надеются, что книга станет источником вдохновения и руководством к действию для многих профессиональных программистов.

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT