Відповіді:
Як зазначають кілька інших, загалом це не проблема.
Єдиний випадок, який викличе у вас проблеми, - це якщо ви повернетеся в середину використовуючого оператора та додатково повернете змінну за допомогою. Але знову ж таки, це також спричинить проблеми, навіть якщо ви не повернетесь і просто зберегли посилання на змінну.
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
заяву досить безглуздою --- саме тому це не те, що вона робить.
Компілятор гарантує, що об’єкт розміщений до того, як контроль покине блок - незалежно від того, як він залишає блок.
Це абсолютно добре - зовсім не проблема. Чому ви вважаєте, що це неправильно?
Оператор, що використовує, - це лише синтаксичний цукор для блоку спробу / нарешті, і, як каже Grzenio, також непогано повертатися і з блоку спробу.
Вираз повернення буде оцінено, потім остаточно буде виконаний блок, потім повернеться метод.
Це цілком прийнятно. Використовуючи оператор забезпечує IDisposable об'єкт буде розташований ні на що.
Від MSDN :
Оператор, що використовує, забезпечує виклик Dispose, навіть якщо виняток виникає під час виклику методів на об'єкті. Ви можете досягти такого ж результату, помістивши об'єкт всередину спробу блоку, а потім викликаючи Dispose в остаточному блоці; насправді, саме так компілятор перекладає використовуючий оператор.
Нижче наведено код 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();
}