Risposte:
Come molti altri hanno sottolineato in generale, questo non è un problema.
L'unico caso che causerà problemi è se si ritorna nel mezzo di un'istruzione using e si restituisce inoltre la variabile in using. Ma, di nuovo, ciò causerebbe problemi anche se non si è tornati e si è semplicemente tenuto un riferimento a una variabile.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Altrettanto male
Something y;
using ( var x = new Something() ) {
y = x;
}
return
istruzione rende la fine del using
blocco inaccessibile da qualsiasi percorso del codice. La fine del using
blocco deve essere eseguita in modo che l'oggetto possa essere disposto, se necessario.
Va benissimo.
Apparentemente lo stai pensando
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
è tradotto alla cieca in:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
Il che, è vero, sarebbe un problema e renderebbe la using
frase piuttosto inutile --- ed è per questo che non è quello che fa.
Il compilatore si assicura che l'oggetto sia disposto prima che il controllo lasci il blocco, indipendentemente da come lascia il blocco.
Va assolutamente bene, nessun problema. Perché credi che sia sbagliato?
Un'istruzione using è solo zucchero sintattico per un blocco try / finally, e come dice Grzenio va bene tornare anche da un blocco try.
L'espressione di ritorno verrà valutata, quindi verrà eseguito il blocco finally, quindi verrà restituito il metodo.
Questo è assolutamente accettabile. Un'istruzione using garantisce che l'oggetto IDisposable verrà eliminato, qualunque cosa accada.
Da MSDN :
L'istruzione using assicura che venga chiamato Dispose anche se si verifica un'eccezione mentre si chiamano metodi sull'oggetto. È possibile ottenere lo stesso risultato inserendo l'oggetto in un blocco try e quindi chiamando Dispose in un blocco finally; in effetti, è così che l'istruzione using viene tradotta dal compilatore.
Il codice seguente mostra come using
funziona:
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());
}
Produzione:
't1' è stato creato.
't2' è stato creato.
't3' è stato creato.
Viene creato 'Creato da t1, t2, t3'.
't3' è eliminato.
't2' è eliminato.
't1' è eliminato.
Gli eliminati vengono chiamati dopo l'istruzione return ma prima dell'uscita della funzione.
Forse non è vero al 100% che questo è accettabile ...
Se ti capita di annidare le usanze e di rientrare da una nidificata, potrebbe non essere sicuro.
Prendi questo come esempio:
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();
}
}
}
Stavo passando un DataTable per essere emesso come CSV. Con il ritorno nel mezzo, stava scrivendo tutte le righe nello stream, ma al csv emesso mancava sempre una riga (o più, a seconda della dimensione del buffer). Questo mi ha detto che qualcosa non veniva chiuso correttamente.
Il modo corretto è assicurarsi che tutti gli utilizzi precedenti siano smaltiti correttamente:
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();
}