У меня есть следующий код
using(MemoryStream ms = new MemoryStream())
{
//code
return 0;
}
dispose()
в конце метода называют using
фигурные скобки оператора }
правильно? Так как я return
до конца using
оператор, будет MemoryStream
возразить быть расположенными правильно? Что происходит здесь?
Да, Dispose
будет вызван. Он вызывается, как только выполнение покидает область действия блока using
, независимо от того, каким способом оно покинуло блок, будь то конец выполнения блока, оператор return
или исключение.
Как правильно отмечает @Noldorin, использование блока using
в коде компилируется в try
/finally
, при этом Dispose
вызывается в блоке finally
. Например, следующий код:
using(MemoryStream ms = new MemoryStream())
{
//code
return 0;
}
фактически становится:
MemoryStream ms = new MemoryStream();
try
{
// code
return 0;
}
finally
{
ms.Dispose();
}
Итак, поскольку finally
гарантированно выполняется после завершения выполнения блока try
, независимо от пути его выполнения, Dispose
гарантированно будет вызван, независимо ни от чего.
Для получения дополнительной информации см. эту статью MSDN.
Дополнение:
Небольшое предостережение: поскольку Dispose
гарантированно вызывается, почти всегда полезно убедиться, что Dispose
никогда не выбрасывает исключение, когда вы реализуете IDisposable
. К сожалению, есть некоторые классы в основной библиотеке, которые делают исключение при определенных обстоятельствах, когда Dispose
вызывается - я смотрю на вас, WCF Service Reference / Client Proxy! -- и когда это происходит, может быть очень трудно отследить исходное исключение, если Dispose
был вызван во время разворачивания стека исключений, поскольку исходное исключение будет проглочено в пользу нового исключения, сгенерированного вызовом Dispose
. Это может быть безумно неприятно. Или это расстраивает? Одно из двух. Возможно, и то, и другое.
using
ведут себя точно так же, как блоки try ... finally
, поэтому всегда будут выполняться на любых путях выхода кода. Однако я считаю, что они подвержены очень немногим и редким ситуациям, в которых блоки finally
не вызываются. Я могу вспомнить один пример: если поток переднего плана завершается, когда фоновые потоки активны: все потоки, кроме GC, приостанавливаются, то есть блоки , наконец,
не запускаются.
Очевидное изменение: они ведут себя одинаково, за исключением логики, которая позволяет им обрабатывать IDisposable объекты, ооо.
Дополнительный контент: их можно складывать друг в друга (если типы различаются):
using (SqlConnection conn = new SqlConnection("string"))
using (SqlCommand comm = new SqlCommand("", conn))
{
}
А также с разделителями-запятыми (где типы совпадают):
using (SqlCommand comm = new SqlCommand("", conn),
SqlCommand comm2 = new SqlCommand("", conn))
{
}
Ваш объект MemoryStream будет утилизирован должным образом, об этом не нужно беспокоиться.
С помощью оператора using
объект будет утилизирован независимо от пути завершения.
Дальнейшее чтение...
Взгляните на свой код в отражателе после его компиляции. Вы обнаружите, что компилятор реорганизует код, чтобы гарантировать, что dispose вызывается в потоке.