Возвращение в середине используемого блока

Что-то вроде:

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

Я считаю, что это неправильное место для оператора return, не так ли?

Ответ 1

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

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

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

Как плохой

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

Ответ 2

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

По-видимому, вы думаете, что

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Это вполне приемлемо. Оператор using гарантирует, что объект IDisposable будет размещен независимо от того, что.

От MSDN:

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

Ответ 6

В приведенном ниже коде показано, как работает 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, но перед выходом из функции.

Ответ 7

Возможно, это не на 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();
}

Я не уверен, где именно проблема, возможно, в распоряжении CsvWriter, или это может быть системная вещь С#? Идеи?