Ответы:
Как отметили несколько других в целом, это не проблема.
Единственный случай, когда это вызовет у вас проблемы, - это если вы вернетесь в середине оператора using и дополнительно вернете переменную using. Но опять же, это также может вызвать проблемы, даже если вы не вернетесь и просто сохраните ссылку на переменную.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Так же плохо
Something y;
using ( var x = new Something() ) {
y = x;
}
return
оператор делает конец using
блока недоступным для любых путей кода. Конец using
блока должен быть пройден, чтобы при необходимости объект можно было утилизировать.
Это прекрасно.
Вы, очевидно, думаете, что
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
слепо переводится на:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
Что, по общему признанию, было бы проблемой, и сделало бы using
заявление довольно бессмысленным - вот почему это не то, что он делает.
Компилятор обеспечивает удаление объекта до того, как элемент управления покидает блок - независимо от того, как он покидает блок.
Это абсолютно нормально - никаких проблем. Почему вы считаете, что это неправильно?
Оператор using - это всего лишь синтаксический сахар для блока try / finally, и, как говорит Грженио, можно также вернуться из блока try.
Возвращаемое выражение будет оценено, затем будет выполнен блок finally, затем метод вернется.
Это полностью приемлемо. Используя оператор обеспечивает IDisposable объект будет расположен ни на что.
Из MSDN :
Оператор using гарантирует, что Dispose вызывается, даже если возникает исключение во время вызова методов для объекта. Вы можете достичь того же результата, поместив объект в блок try, а затем вызвав Dispose в блоке finally; на самом деле, именно так оператор using переводится компилятором.
Код ниже показывает, как using
работает:
private class TestClass : IDisposable
{
private readonly string id;
public TestClass(string id)
{
Console.WriteLine("'{0}' is created.", id);
this.id = id;
}
public void Dispose()
{
Console.WriteLine("'{0}' is disposed.", id);
}
public override string ToString()
{
return id;
}
}
private static TestClass TestUsingClose()
{
using (var t1 = new TestClass("t1"))
{
using (var t2 = new TestClass("t2"))
{
using (var t3 = new TestClass("t3"))
{
return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
}
}
}
}
[TestMethod]
public void Test()
{
Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}
Вывод:
't1' создан.
't2' создан.
't3' создан.
«Создано из t1, t2, t3» создано.
't3' расположен.
't2' расположен.
't1' расположен.
Распоряжение вызывается после оператора return, но перед выходом из функции.
Возможно, это не на 100% правда, что это приемлемо ...
Если вам случится вложить и вернуться из вложенного, это может быть небезопасно.
Возьмите это как пример:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
return memoryStream.ToArray();
}
}
}
Я передавал DataTable для вывода в виде CSV. С возвратом в середине он записывал все строки в поток, но в выводимом csv всегда отсутствовала строка (или несколько, в зависимости от размера буфера). Это сказало мне, что что-то не было закрыто должным образом.
Правильный способ - убедиться, что все предыдущие использования расположены правильно:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
}
}
return memoryStream.ToArray();
}