Язык программирования C#9 и платформа .NET5
Повторное использование ключевого слова using в C#
Имея дело с управляемым объектом, который реализует интерфейс
, довольно часто приходится применять структурированную обработку исключений, гарантируя тем самым, что методIDisposableтипа будет вызываться даже в случае генерации исключения во время выполнения:Dispose()Console.WriteLine("***** Fun with Dispose *****\n");MyResourceWrapper rw = new MyResourceWrapper ();try{// Использовать члены rw.}finally{// Всегда вызывать Dispose(), возникла ошибка или нет.rw.Dispose();}Хотя это является хорошим примером защитного программирования, в действительности лишь немногих разработчиков привлекает перспектива помещения каждого освобождаемого типа внутрь блока
, просто чтобы гарантировать вызов методаtry/finally. Того же самого результата можно достичь гораздо менее навязчивым способом, используя специальный фрагмент синтаксиса С#, который выглядит следующим образом:Dispose()Console.WriteLine("***** Fun with Dispose *****\n");// Метод Dispose() вызывается автоматически// при выходе за пределы области действия using.using(MyResourceWrapper rw = new MyResourceWrapper()){// Использовать объект rw.}Если вы просмотрите код CIL операторов верхнего уровня посредством
, то обнаружите, что синтаксисildasm.exeна самом деле расширяется до логикиusingс вполне ожидаемым вызовомtry/finally:Dispose().method private hidebysig static void'<Main>$'(string[] args) cil managed{....try{} // end .tryfinally{IL_0019: callvirt instance void [System.Runtime]System.IDisposable::Dispose()} // end handler} // end of method '<Program>$'::'<Main>$'На заметку! Попытка применения
к объекту, который не реализует интерфейсusing, приводит к ошибке на этапе компиляции.IDisposableНесмотря на то что такой синтаксис устраняет необходимость вручную помещать освобождаемые объекты внутрь блоков
, к сожалению, теперь ключевое словоtry/finallyв C# имеет двойной смысл (импортирование пространств имен и вызов методаusing). Однако при работе с типами, которые поддерживают интерфейсDispose(), такая синтаксическая конструкция будет гарантировать, что используемый объект автоматический вызовет свой методIDisposableпо завершении блокаDispose().usingКроме того, имейте в виду, что внутри
допускается объявлять несколько объектов одного и того же типа. Как и можно было ожидать, компилятор вставит код для вызоваusingна каждом объявленном объекте:Dispose()// Использовать список с разделителями-запятыми для объявления// нескольких объектов, подлежащих освобождению.using(MyResourceWrapper rw = new MyResourceWrapper(),rw2 = new MyResourceWrapper()){// Работать с объектами rw и rw2.}Объявления using (нововведение в версии 8.0)
В версии C# 8.0 были добавлены объявления
. Объявлениеusingпредставляет собой объявление переменной, предваренное ключевым словомusing. Функциональность объявленияusingбудет такой же, как у синтаксиса, описанного в предыдущем разделе, за исключением явного блока кода, помещенного внутрь фигурных скобок (using).{}Добавьте к своему классу следующий метод:
private static void UsingDeclaration(){// Эта переменная будет находиться в области видимости// вплоть до конца метода.using var rw = new MyResourceWrapper();// Сделать что-нибудь.Console.WriteLine("About to dispose.");// В этой точке переменная освобождается.}Далее добавьте к своим операторам верхнего уровня показанный ниже вызов:
Console.WriteLine("***** Fun with Dispose *****\n");...Console.WriteLine("Demonstrate using declarations");UsingDeclaration();Console.ReadLine();Если вы изучите новый метод с помощью
, то (вполне ожидаемо) обнаружите тот же код, что и ранее:ildasm.exe.method private hidebysig staticvoid UsingDeclaration() cil managed