Y a-t-il des effets secondaires du retour de l'intérieur d'une instruction using ()?

125

De retour d' une valeur de la méthode de l' intérieur d' une instruction à l' aide qui obtient un DataContext semble toujours un travail bien , comme ceci:

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

Mais je me sens toujours que je devrais fermais quelque chose avant de sortir des supports à l' aide, par exemple par transaction définissant avant l'instruction à l' aide, obtenir la valeur de ce à l' intérieur des crochets, puis de revenir après les parenthèses.

La définition et le renvoi de la variable en dehors des crochets d'utilisation seraient-ils une meilleure pratique ou conserveraient-ils les ressources de quelque manière que ce soit?

Edward Tanguay
la source
1
Il pourrait être intéressant de regarder l'IL générale pour des variantes de ceci. Je soupçonne qu'il y aurait peu de différence dans l'IL généré. Normalement, je ne prendrais même pas la peine de déclarer la transaction var - renvoyez simplement le résultat de l'expression.
Jonesie

Réponses:

164

Non, je pense que c'est plus clair de cette façon. Ne vous inquiétez pas, Disposesera toujours appelé "à la sortie" - et seulement après que la valeur de retour est entièrement évaluée. Si une exception est levée à tout moment (y compris l'évaluation de la valeur de retour) Disposesera toujours appelée aussi.

Alors que vous avez certainement pu prendre la route plus longue, il est deux lignes supplémentaires qui ajoutent juste cochonneries et le contexte supplémentaire pour garder une trace de (mentalement). En fait, vous n'avez pas vraiment besoin de la variable locale supplémentaire - bien qu'elle puisse être pratique en termes de débogage. Vous pourriez juste avoir:

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

En effet, je pourrais même être tenté d'utiliser la notation par points, et de mettre la Wherecondition dans le SingleOrDefault:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}
Jon Skeet
la source
2
Si c'est vous @jon, est-ce toujours sûr si une exception est levée à l'intérieur du bloc using?
Dave Archer
6
Oui. l'utilisation est simplement du sucre syntaxique pour une construction try / finally
Mitch Wheat
@David: Comme le dit Mitch, ça va - j'ai mis à jour la réponse pour clarifier cela :)
Jon Skeet
2
Pourquoi utiliser OrderByDescending en combinaison avec SingleOrDefault?
erikkallen
2
@erikkallen: LINQ n'a malheureusement pas de "MaxBy", donc vous ne pouvez pas obtenir la ligne avec la valeur maximale. Pour LINQ to Objects, vous pouvez écrire le vôtre assez facilement, mais je ne suis pas sûr d'une meilleure façon de le faire dans ce cas. Que suggéreriez-vous à la place?
Jon Skeet
32

Jetez un œil à ceci

Comprendre l'instruction 'using' en C #

Le CLR convertit votre code en MSIL. Et l'instruction using est traduite en un bloc try and finally. C'est ainsi que l'instruction using est représentée dans IL. Une déclaration d'utilisation est traduite en trois parties: acquisition, utilisation et élimination. La ressource est d'abord acquise, puis l'utilisation est incluse dans une instruction try avec une clause finally. L'objet est ensuite supprimé dans la clause finally.

Adriaan Stander
la source
4
Un aperçu intéressant. Merci.
Kangkan
1
Cela traduit la question en: Y a-t-il des effets secondaires du retour du bloc try d'un try-finally?
Henk Holterman
3
Non, le finalement sera toujours appelé. techinterviews.com/interview-questions-for-c-developers
Adriaan Stander
6

Il n'y a pas d' effets secondaires du retour de l'intérieur d'une using()déclaration.

La question de savoir si cela rend le code le plus lisible est une autre discussion.

Blé Mitch
la source
0

Je pense que c'est pareil. Il n'y a rien de mal dans le code. Le framework .NET ne se soucierait pas de l'emplacement de création de l'objet. Ce qui compte, c'est de savoir s'il est référencé ou non.

Kerido
la source
-1

Oui, il peut y avoir un effet secondaire. Par exemple, si vous utilisez la même technique dans la méthode Action ASP.NET MVC, vous obtiendrez l'erreur suivante: «L'instance ObjectContext a été supprimée et ne peut plus être utilisée pour les opérations qui nécessitent une connexion»

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);
    }
}
utileBee
la source
2
si vous définissez une transaction en dehors de l'instruction using, vous obtiendrez la même erreur. L'utilisation du mot clé n'est pas liée dans ce cas.
Costa