Используя using

Один из моих самых любимых вопросов на собеседовании: в чём опасность такой конструкции?

…
using (MyClass myClass = new MyClass() { Prop = p })
{
    myClass.Use();
}

Выглядит вполне невинно — до тех пор, пока не начинаешь задумываться в том, как это устроено внутри.
В самом деле, конструкция using является «синтаксическим сахаром» вокруг try-finally, предназначенным для более лаконичной и удобной работы с неуправляемыми ресурсами ОС, такими, как файловые дескрипторы или сетевые соединения (в том числе с базами данных). Кратко напомню, что неуправляемые ресурсы, захваченные во время жизни объекта, принято освобождать в специально предназначенном для этого методе IDisposable.Dispose, реализовав, естественно, интерфейс IDisposable в захватывающем неуправляемые ресурсы классе.
Вышеприведённый using разворачивается примерно вот в такую конструкцию:

…
MyClass myClass = new MyClass() { Prop = p };
try
{
    myClass.Use();
}
finally
{
    if(myClass != null)
        ((IDisposable)myClass).Dispose();
}

…а если развернуть ещё и инициализатор — то получится вовсе что-то этакое:

…
MyClass myClass = new MyClass();
myClass.Prop = p;
try
{
    myClass.Use();
}
finally
{
    if(myClass != null)
        ((IDisposable)myClass).Dispose();
}

И уже отсюда видно, что между конструктором (где, как правило, захватываются ресурсы) и try-finally блоком (где гарантируется их освобождение при почти любых раскладах) находится строка «myClass.Prop = p;», и в сеттере свойства Prop может быть выброшено исключение. В этой ситуации ссылка на myClass будет утеряна, и вызвать метод Dispose (а, следовательно, и освободить захваченные ресурсы) будет невозможно, а это очень-очень плохо (англ.).
В этом и заключается опасность использования инициализаторов при создании класса, захватывающего неуправляемые ресурсы.
Более безопасный (хотя и не столь изящный) способ сделать это:

…
using (MyClass myClass = new MyClass())
{
    myClass.Prop = p;
    myClass.Use();
}

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s