Algo así como:regresar en medio de un bloque mediante
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
creo que no es un lugar adecuado para una instrucción de retorno, ¿verdad?
Algo así como:regresar en medio de un bloque mediante
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
creo que no es un lugar adecuado para una instrucción de retorno, ¿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 instrucción de uso y, además, devuelve la variable de entrada usando. 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;
}
esto va a funcionar perfectamente bien, al igual que de regresar en medio de try{}finally{}
que es totalmente aceptable. Una declaración usando asegura que el objeto IDisposable será eliminado sin importar qué.
De MSDN:
La instrucción using asegura que Desechar se llama incluso si se produce una excepción, mientras que la que está llamando a métodos en el 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 compilador traduce la sentencia using.
Está absolutamente bien, no hay problema en absoluto. ¿Por qué crees que está mal?
Una declaración de uso es solo azúcar sintáctico para un bloque try/finally, y como Grzenio dice que está bien regresar también de un bloque try.
Se evaluará la expresión de retorno, luego se ejecutará el bloque finally, luego se devolverá el método.
La respuesta de James Curran explica lo que estaba pensando. – tafa
Está perfectamente bien.
Usted está aparentemente pensando que
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
se traduce a ciegas en:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
que, sin duda, sería un problema, y haría que la declaración using
bastante inútil --- que es por qué eso es no qué hace.
El compilador se asegura de que el objeto se elimine antes de que el control abandone el bloque, independientemente de cómo abandone el bloque.
Yo estaba, aparentemente. – tafa
¡Gran respuesta @James Curran! Pero me hace bastante curioso lo que se traduce en. ¿O eso solo se puede expresar en IL? (que nunca he intentado leer antes). – Bart
@Bart - Lo considero como una evaluación de la expresión de retorno en una variable temporal, luego haciendo el desecho, y luego devolviendo la variable temporal. – ToolmakerSteve
Tal vez no es 100% cierto que esto es aceptable ...
Si le sucede a ser usings anidación y regresar desde el interior de una anidada , puede que no sea seguro.
tomar 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();
}
}
}
yo estaba pasando en un DataTable a ser emitida 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 usings anteriores están bien dispuestos:
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();
}
El fuelle de código muestra cómo using
está trabajando:
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.
se crea 't3'.
'Creado desde t1, t2, t3' se crea.
't3' está dispuesto.
't2' está eliminado.
't1' está eliminado.
Los llamados se llaman después de la declaración de devolución pero antes de la salida de la función.
Solo estaba a punto de editar mi pregunta sobre el punto que mencionaste. Gracias. – tafa
Por favor, ayúdame a entender por qué esto es malo. Me gustaría devolver un Stream que estoy usando en una función auxiliar a otra función para el procesamiento de imágenes. Parece que el Stream se eliminará si hago esto? –
@JohnShedletsky En este caso, su llamada de función debe ser envuelta con el uso. Me gusta usar (Stream x = FuncToReturnStream()) {...} y no usar dentro de FuncToReturnStream. –