2009-03-19 3 views

ответ

149

Как уже указывали другие, это не проблема.

Единственный случай, из-за которого возникают проблемы, если вы возвращаетесь в середине оператора using и дополнительно возвращаете переменную using. Но опять же, это также вызовет проблемы, даже если вы не вернетесь и просто сохраните ссылку на переменную.

using (var x = new Something()) { 
    // not a good idea 
    return x; 
} 

Подобно тому, как плохо

Something y; 
using (var x = new Something()) { 
    y = x; 
} 
+1

Просто я собирался изменить свой вопрос о том, что вы упомянули. Благодарю. – tafa

+0

Пожалуйста, помогите мне понять, почему это плохо. Я хотел бы вернуть Stream, который я использую в вспомогательной функции для другой функции обработки изображений. Кажется, что Stream будет утилизирован, если я это сделаю? –

+1

@JohnShedletsky В этом случае вызов функции должен быть завернут с использованием. Подобно использованию (Stream x = FuncToReturnStream()) {...} и без использования внутри FuncToReturnStream. –

23

Это будет работать прекрасно, так же, как возвращение в середине try{}finally{}

14

То есть вполне приемлемо. A с использованием инструкции гарантирует, что объект IDisposable будет размещен независимо от того, что.

От MSDN:

используя оператор гарантирует, что Dispose вызывается даже если исключение происходит во время вызова методов объекта. Вы можете добиться того же результата, поставив объект внутри блока try и затем вызывая Dispose в блоке finally; Фактически, это то, как оператор using преобразуется компилятором.

85

Это абсолютно нормально - проблем нет. Почему вы считаете, что это неправильно?

Оператор using - это просто синтаксический сахар для блока try/finally, и, поскольку Grzenio говорит, что также хорошо вернуться из блока try.

Выражение return будет оценено, тогда блок finally будет выполнен, после чего метод вернется.

+5

Ответ Джеймса Каррана объясняет, о чем я думал. – tafa

96

Это прекрасно.

Вы, видимо, полагая, что

using (IDisposable disposable = GetSomeDisposable()) 
{ 
    //..... 
    //...... 
    return Stg(); 
} 

слепо переводится на:

IDisposable disposable = GetSomeDisposable() 
//..... 
//...... 
return Stg(); 
disposable.Dispose(); 

Который, правда, было бы проблемой, и сделает using заявление довольно бессмысленным --- что почему это нет что это.

Компилятор гарантирует, что объект будет удален до того, как управление покинет блок - независимо от того, как он покинет блок.

+5

Я был, по-видимому. – tafa

+0

Отличный ответ @James Curran! Но мне очень любопытно, на что он переведен. Или это только выражается в IL? (который я никогда не пытался прочитать раньше). – Bart

+0

@Bart - я думаю об этом, оценивая выражение return во временную переменную, а затем выполняю команду, затем возвращаю временную переменную. – ToolmakerSteve

-3

Возможно, это не 100% верно, что это приемлемо ...

Если вам случится быть гнездовые usings и возвращение во вложенном одного , это может быть небезопасно.

Возьмите это в качестве примера:

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 всегда отсутствовала строка (или несколько, в зависимости от размера буфера). Это сказало мне, что что-то не закрывается должным образом.

Правильный путь, чтобы убедиться, что все предыдущие usings расположены правильно:

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(); 
} 
1

код ниже показывает, как 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' расположен.

Расположенные вызывается после оператора возврата, но до выхода из функции.