Odpowiedzi:
Jak kilka innych ogólnie wskazało, nie stanowi to problemu.
Jedynym przypadkiem, który spowoduje problemy, jest powrót w środku instrukcji using i dodatkowo zwrócenie zmiennej using. Ale z drugiej strony spowoduje to również problemy, nawet jeśli nie wrócisz i po prostu zachowasz odwołanie 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;
}
return
instrukcja powoduje, że koniec using
bloku jest niedostępny dla dowolnej ścieżki kodu. Koniec using
bloku musi zostać uruchomiony, aby obiekt mógł zostać usunięty w razie potrzeby.
Jest całkowicie w porządku.
Najwyraźniej tak myślisz
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
jest ślepo tłumaczone na:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
Co, co prawda, stanowiłoby problem i uczyniłoby to using
stwierdzenie raczej bezcelowym - dlatego nie robi tego.
Kompilator upewnia się, że obiekt jest usuwany, zanim formant opuści blok - niezależnie od tego, jak opuści blok.
Jest absolutnie w porządku - nie ma problemu. Dlaczego uważasz, że to źle?
Instrukcja using to po prostu cukier składniowy dla bloku try / last, a jak mówi Grzenio, powrót z bloku try może być w porządku.
Wyrażenie zwrotne zostanie ocenione, następnie zostanie wykonany blok w końcu, a następnie metoda powróci.
To jest całkowicie do przyjęcia. Użyciu oświadczenie zapewnia, że IDisposable obiekt zostanie umieszczony nie wiem co.
Z MSDN :
Instrukcja using zapewnia, że wywoływana jest funkcja Dispose, nawet jeśli wystąpi wyjątek podczas wywoływania metod na obiekcie. Możesz osiągnąć ten sam wynik, umieszczając obiekt w bloku try, a następnie wywołując Dispose w bloku wreszcie; w rzeczywistości tak kompilator tłumaczy instrukcję using.
Poniższy kod pokazuje, jak using
działa:
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());
}
Wynik:
Utworzono „t1”.
Utworzono „t2”.
Utworzono „t3”.
Utworzono „Utworzono z t1, t2, t3”.
„t3” jest usuwane.
„t2” jest usuwane.
„t1” jest usuwane.
Pozbywane są wywoływane po instrukcji return, ale przed wyjściem z funkcji.
Być może nie jest w 100% prawdą, że jest to dopuszczalne ...
Jeśli akurat zagnieżdżasz użytki i wracasz z zagnieżdżonego, może to nie być bezpieczne.
Weź 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();
}
}
}
Podawałem DataTable, która ma być wyprowadzana jako csv. Z powrotem w środku zapisywał wszystkie wiersze w strumieniu, ale w wyjściowym pliku csv zawsze brakowało wiersza (lub wielokrotności, w zależności od wielkości bufora). To powiedziało mi, że coś nie zostało poprawnie zamknięte.
Prawidłowym sposobem jest upewnienie się, że wszystkie poprzednie zastosowania zostały odpowiednio 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();
}