Подтвердить что ты не робот

Пустое выражение "using" в Dispose

Недавно я увидел код, написанный следующим образом:

public void Dipose()
{
   using(_myDisposableField) { }
}

Мне кажется, это довольно странно, я бы предпочел увидеть myDisposableField.Dispose();

Какие существуют причины для использования "использования" для утилизации объектов, явно вызывающих вызов?

4b9b3361

Ответ 1

Нет, совсем нет. Он просто скомпилируется в пустой try/finally и в итоге вызывает Dispose.

Удалите его. Вы сделаете код более быстрым, читабельным и, возможно, самым важным (как вы продолжите читать ниже) более выразительным в своем намерении.

Обновить: они были немного умны, эквивалентный код нуждается в нулевой проверке и в соответствии с рекомендацией Джона Скита, также возьмите локальную копию, если задействована многопоточность (точно так же, как стандарт шаблон вызова события, чтобы избежать гонки между нулевой проверкой и вызовом метода).

IDisposable tmp = _myDisposableField; 

if (tmp != null) 
    tmp.Dispose();

Из того, что я вижу в IL примерного приложения, которое я написал, похоже, вам также нужно обращаться с _myDisposableField как IDisposable напрямую. Это будет важно, если любой тип реализует IDisposable интерфейс явно, а также предоставляет метод public void Dispose() в то же время.

Этот код также не пытается реплицировать try-finally, который существует при использовании using, но считается, что это считается ненужным. Однако, как отмечает Michael Graczyk в комментариях, использование finally обеспечивает защиту от исключений, в частности, ThreadAbortException (что может произойти в любой точке). Тем не менее, окно для этого действительно произойдет очень мало.

Хотя, я сделал бы ставку на то, что они действительно не понимали, какие тонкие "преимущества" они им дали.

Ответ 2

В примере, который вы опубликовали, есть очень тонкая, но злая ошибка.

Пока он "скомпилируется" до:

try {}
finally
{
    if (_myDisposableField != null) 
        ((IDisposable)_myDisposableField).Dispose();
}
Объекты

должны быть созданы в контексте использования, а не снаружи:

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

using Statement (ссылка на С#)

Другими словами, он грязный и взломанный.

Чистая версия чрезвычайно четко прописана в MSDN:

  • если вы можете ограничить использование экземпляра методом, затем используйте блок using с вызовом конструктора на его границе. Не используйте Dispose напрямую.
  • если вам нужно (но действительно необходимо) сохранить экземпляр в активном состоянии до тех пор, пока родитель не будет удален, затем явно решите использовать одноразовый шаблон и ничего остальное. Существуют различные способы реализации каскада dispose, однако они должны быть выполнены так же, чтобы избежать очень тонких и трудно улавливаемых ошибок. Там есть очень хороший ресурс в MSDN в Руководстве по разработке каркаса.

Наконец, обратите внимание на следующее: вы должны использовать шаблон IDisposable, если используете неуправляемые ресурсы. Убедитесь, что это действительно необходимо: -)

Ответ 3

Оператор using определяет диапазон кода, после которого объект, на который ссылается, должен быть удален.

Да, вы могли бы просто вызвать .dispose, как только это было сделано, но было бы менее ясно (IMHO), какова область действия объекта. YMMV.