volviendo en el medio de un bloque que usa

Algo como:

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

Creo que no es un lugar apropiado para una statement de devolución, ¿verdad?

Como muchos otros han señalado en general, esto no es un problema.

El único caso que le causará problemas es si regresa a la mitad de una statement de uso y, además, devuelve la variable de uso. Pero, de nuevo, esto también causaría problemas incluso si no regresó y simplemente guardó una referencia a una variable.

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

Tan malo

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

Está perfectamente bien.

Al parecer estás pensando que

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

se traduce ciegamente en:

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

Lo cual, ciertamente, sería un problema, y ​​haría que la statement de using inútil, y por eso no es eso lo que hace.

El comstackdor se asegura de que el objeto se elimine antes de que el control abandone el bloque, independientemente de cómo abandone el bloque.

Está absolutamente bien, no hay problema en absoluto. ¿Por qué crees que está mal?

Una statement de uso es solo azúcar sintáctica para un bloque try / finally, y como Grzenio dice que está bien regresar también de un bloque try.

La expresión de retorno será evaluada, luego se ejecutará el bloque finally, luego el método retornará.

Esto funcionará perfectamente bien, al igual que regresar en el medio de try{}finally{}

Eso es totalmente aceptable. Una statement using garantiza que el objeto IDisposable se eliminará sin importar qué.

Desde MSDN :

La instrucción using garantiza que se invoque Dispose incluso si se produce una excepción mientras se están llamando métodos al objeto. Puede lograr el mismo resultado colocando el objeto dentro de un bloque try y luego llamando a Dispose en un bloque finally; de hecho, así es como el comstackdor traduce la sentencia using.

El siguiente código muestra cómo está funcionando el uso:

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

Salida:

‘t1’ es creado.
‘t2’ es creado.
‘t3’ es creado.
‘Creado desde t1, t2, t3’ es creado.
‘t3’ está dispuesto.
‘t2’ está dispuesto.
‘t1’ está dispuesto.

Los eliminados se llaman después de la statement de devolución pero antes de la salida de la función.

Tal vez no sea 100% cierto que esto sea aceptable …

Si está anidando usos y regresando desde uno nested, puede que no sea seguro.

Toma esto como un ejemplo:

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

Estaba pasando un DataTable para que salga como csv. Con el retorno en el medio, estaba escribiendo todas las filas en la secuencia, pero al csv de salida siempre le faltaba una fila (o múltiple, dependiendo del tamaño del búfer). Esto me dijo que algo no se cerraba correctamente.

La forma correcta es asegurarse de que todos los usos anteriores se eliminen correctamente:

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