powrót w środku bloku

Coś w stylu:

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}
Uważam, że to nie jest właściwe miejsce na oświadczenie zwrotne, prawda?
Author: tafa, 2009-03-19

7 answers

Jak kilka innych wskazało ogólnie, nie jest to problem.

Jedynym przypadkiem, który spowoduje problemy, jest zwrócenie w środku instrukcji using I dodatkowo zwrócenie zmiennej in using. Ale z drugiej strony, spowodowałoby to również problemy, nawet jeśli nie powrócisz i po prostu zachowasz odniesienie do zmiennej.

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

Tak samo źle

Something y;
using ( var x = new Something() ) {
  y = x;
}
 168
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-19 16:02:18

Wszystko w porządku.

Najwyraźniej myślisz, że

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

Jest ślepo tłumaczone na:

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

Co, Co prawda, byłoby problemem, i uczyniłoby using stwierdzenie raczej bezsensownym - - - dlatego to jest , a nie to, co robi.

Kompilator upewnia się, że obiekt zostanie usunięty zanim control opuści blok-niezależnie od tego jak opuści blok.

 112
Author: James Curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-19 16:01:54

Jest absolutnie w porządku - żaden problem. Dlaczego uważasz, że to złe?

Wyrażenie using jest tylko składniowym cukrem dla bloku try / finally i jak mówi Grzenio, dobrze jest też wrócić z bloku try.

Zostanie obliczone wyrażenie zwrotne, następnie zostanie wykonany finally block, a następnie metoda powróci.

 89
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-19 15:56:53

To będzie działać idealnie, tak jak powrót w środku try{}finally{}

 25
Author: Grzenio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-19 15:55:30

To jest całkowicie dopuszczalne. użycie instrukcji zapewnia, że IDisposable obiekt zostanie usunięty bez względu na wszystko.

From MSDN :

Instrukcja using zapewnia, że Dispose jest wywoływane nawet wtedy, gdy wystąpi wyjątek podczas wywoływania metod w obiekcie. Można osiągnąć ten sam wynik, umieszczając obiekt wewnątrz bloku try, a następnie wywołując Dispose w bloku finally; w rzeczywistości tak jest przetłumaczone polecenie using kompilator.

 16
Author: mbillard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-19 15:56:05

Poniższy kod pokazuje jak działa 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());
}

Wyjście:

Tworzony jest't1'.
powstaje "t2".
powstaje "t3".
Tworzy się "utworzone z t1, t2, t3".
"t3" jest usuwany.
"t2" jest usuwany.
"t1" jest usuwany.

Disposed są wywoływane po instrukcji return, ale przed zakończeniem funkcji.

 7
Author: Bertrand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-02 09:35:38

Być może nie jest to w 100% prawdą, że jest to dopuszczalne...

Jeśli zdarzy ci się, że zagnieżdżasz się i wracasz z zagnieżdżonego, może to nie być bezpieczne.

Weźmy to jako przykład:

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

Przechodziłem przez DataTable, który miał być wyprowadzony jako csv. Z returnem w środku zapisywał wszystkie wiersze do strumienia, ale w wyjściowym pliku csv zawsze brakowało wiersza (lub wielu, w zależności od rozmiaru bufora). To mi mówiło, że coś nie jest zamknięte. jak należy.

Poprawnym sposobem jest upewnienie się, że wszystkie poprzednie zastosowania są prawidłowo usunięte:

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();
}
 -3
Author: yeahright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 15:45:20