¿Hay algún efecto secundario de regresar desde adentro de una instrucción using ()?


125

Devolver un valor de método desde el interior de una instrucción de uso que obtiene un DataContext parece funcionar siempre bien , así:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return transaction;
    }
}

Pero siempre siento que debería cerrar algo antes de salir de los corchetes de uso, por ejemplo, al definir la transacción antes de la declaración de uso, obtener su valor dentro de los corchetes y luego regresar después de los corchetes.

¿Definir y devolver la variable fuera de los corchetes de uso sería una mejor práctica o conservaría los recursos de alguna manera?


1
Puede ser interesante mirar la IL general para variantes de esto. Sospecho que habría poca diferencia en la IL generada. Normalmente ni siquiera me molestaría en declarar la transacción var, solo devuelvo el resultado de la expresión.
Jonesie

Respuestas:


164

No, creo que es más claro de esta manera. No se preocupe, Disposeseguirá llamándose "al salir", y solo después de que el valor de retorno se haya evaluado por completo. Si se produce una excepción en algún momento (incluida la evaluación del valor de retorno), Disposese seguirá llamando también.

Si bien ciertamente podría tomar la ruta más larga, son dos líneas adicionales que solo agregan cruft y contexto adicional para realizar un seguimiento (mentalmente). De hecho, realmente no necesita la variable local adicional, aunque puede ser útil en términos de depuración. Usted podría simplemente tener:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return (from t in db.Transactions
                orderby t.WhenCreated descending
                where t.Id == singleId
                select t).SingleOrDefault();
    }
}

De hecho, incluso podría sentir la tentación de usar la notación de puntos y poner la Wherecondición dentro de SingleOrDefault:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}

2
Seno, eres tú @ Jon, ¿sigue siendo seguro si se lanza una excepción dentro del bloque de uso?
Dave Archer

66
si. usar es simplemente azúcar sintáctico para un intento / finalmente construir
Mitch Wheat

@David: Como dice Mitch, está bien - He actualizado la respuesta para aclararlo :)
Jon Skeet

2
¿Por qué usar OrderByDescending en combinación con SingleOrDefault?
erikkallen

2
@erikkallen: LINQ no tiene un "MaxBy", desafortunadamente, por lo que no puede obtener la fila con el valor máximo. Para LINQ to Objects, puede escribir el suyo con bastante facilidad, pero no estoy seguro de una mejor manera de hacerlo en este caso. ¿Qué sugerirías en su lugar?
Jon Skeet

32

Echa un vistazo a esto

Comprender la instrucción 'using' en C #

El CLR convierte su código en MSIL. Y la declaración de uso se traduce en un intento y finalmente se bloquea. Así es como se representa la instrucción using en IL. Una declaración de uso se traduce en tres partes: adquisición, uso y eliminación. El recurso se adquiere primero, luego el uso se incluye en una declaración de prueba con una cláusula finalmente El objeto se elimina en la cláusula final.


44
Una idea interesante. Gracias.
Kangkan

1
Eso traduce la pregunta a: ¿Algún efecto secundario de regresar del try-block de un try-finally?
Henk Holterman


6

No hay efectos secundarios de regresar desde dentro de una using()declaración.

Si hace el código más legible es otra discusión.


0

Creo que es todo lo mismo. No hay nada malo en el código. El marco .NET no le importaría dónde se crea el objeto. Lo que importa es si se hace referencia o no.


-1

Sí, puede haber un efecto secundario. Por ejemplo, si usa la misma técnica en el método de Acción ASP.NET MVC, obtendrá el siguiente error: "La instancia de ObjectContext se ha eliminado y ya no se puede usar para operaciones que requieren una conexión"

public ActionResult GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return PartialView("_transactionPartial", transaction);
    }
}

2
si define la transacción fuera del uso de la declaración, obtendrá el mismo error. El uso de la palabra clave no está relacionado en este caso.
Costa
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.