Gibt es irgendwelche Nebenwirkungen bei der Rückkehr aus einer using () -Anweisung?

125

Ein Verfahren Wert von der Rückkehr innerhalb einer using Anweisung , die eine Datacontext bekommt scheint immer Arbeit in Ordnung , wie folgt aus :

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

Aber ich habe immer das Gefühl, ich sollte etwas schließen, bevor ich aus den using-Klammern ausbreche, z. B. indem ich die Transaktion vor der using-Anweisung definiere, ihren Wert in die Klammern bringe und dann nach den Klammern zurückkehre.

Wäre das Definieren und Zurückgeben der Variablen außerhalb der verwendeten Klammern besser oder würden Ressourcen in irgendeiner Weise geschont?

Edward Tanguay
quelle
1
Es könnte interessant sein, in der allgemeinen IL nach Varianten davon zu suchen. Ich vermute, dass es kaum einen Unterschied in der generierten IL geben würde. Normalerweise würde ich mir nicht einmal die Mühe machen, die var-Transaktion zu deklarieren - geben Sie einfach das Ergebnis des Ausdrucks zurück.
Jonesie

Antworten:

164

Nein, ich denke es ist klarer so. Keine Sorge, Disposewird immer noch "auf dem Weg nach draußen" genannt - und erst, nachdem der Rückgabewert vollständig ausgewertet wurde. Wenn zu irgendeinem Zeitpunkt eine Ausnahme ausgelöst wird (einschließlich der Auswertung des Rückgabewerts), Disposewird diese weiterhin aufgerufen.

Während Sie sicherlich den längeren Weg nehmen könnten , sind es zwei zusätzliche Zeilen, die nur Cruft und zusätzlichen Kontext hinzufügen, um (mental) den Überblick zu behalten. Tatsächlich benötigen Sie die zusätzliche lokale Variable nicht wirklich - obwohl dies beim Debuggen hilfreich sein kann. Sie könnten einfach haben:

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

In der Tat könnte ich sogar versucht sein, die Punktnotation zu verwenden und die WhereBedingung in das 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
quelle
2
Da Sie @jon sind, ist es immer noch sicher, wenn eine Ausnahme im using-Block ausgelöst wird?
Dave Archer
6
Ja. Verwenden ist einfach syntaktischer Zucker für einen Versuch / schließlich Konstrukt
Mitch Wheat
@ David: Wie Mitch sagt, ist es in Ordnung - ich habe die Antwort aktualisiert, um das klarer zu machen :)
Jon Skeet
2
Warum OrderByDescending in Kombination mit SingleOrDefault verwenden?
Erikkallen
2
@erikkallen: LINQ hat leider kein "MaxBy" - Sie können also nicht die Zeile mit dem Maximalwert erhalten. Für LINQ to Objects können Sie ziemlich einfach Ihre eigenen schreiben, aber ich bin mir nicht sicher, wie ich es in diesem Fall besser machen kann. Was würden Sie stattdessen vorschlagen?
Jon Skeet
32

Schau dir das an

Grundlegendes zur 'using'-Anweisung in C #

Die CLR konvertiert Ihren Code in MSIL. Und die using-Anweisung wird in einen Versuch übersetzt und schließlich blockiert. So wird die using-Anweisung in IL dargestellt. Eine using-Anweisung besteht aus drei Teilen: Erwerb, Verwendung und Entsorgung. Die Ressource wird zuerst erfasst, dann wird die Verwendung in einer try-Anweisung mit einer finally-Klausel eingeschlossen. Das Objekt wird dann in der finally-Klausel entsorgt.

Adriaan Stander
quelle
4
Ein interessanter Einblick. Vielen Dank.
Kangkan
1
Das übersetzt die Frage in: Gibt es Nebenwirkungen bei der Rückkehr aus dem Try-Block eines Try-Endlich?
Henk Holterman
3
Nein, das wird endlich immer aufgerufen. techinterviews.com/interview-questions-for-c-developers
Adriaan Stander
6

Es gibt keine Nebenwirkungen bei der Rückkehr aus einer using()Anweisung heraus.

Ob es den am besten lesbaren Code macht, ist eine andere Diskussion.

Mitch Wheat
quelle
0

Ich denke, es ist alles das Gleiche. Der Code enthält nichts Schlechtes. Dem .NET Framework ist es egal, wo das Objekt erstellt wird. Entscheidend ist, ob darauf verwiesen wird oder nicht.

Kerido
quelle
-1

Ja, es kann eine Nebenwirkung geben. Wenn Sie beispielsweise dieselbe Technik in der ASP.NET MVC-Aktionsmethode verwenden, wird die folgende Fehlermeldung angezeigt: "Die ObjectContext-Instanz wurde entsorgt und kann nicht mehr für Vorgänge verwendet werden, für die eine Verbindung erforderlich ist."

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);
    }
}
nützlichBee
quelle
2
Wenn Sie eine Transaktion außerhalb der using-Anweisung definieren, wird der gleiche Fehler angezeigt. Die Verwendung des Schlüsselworts hat in diesem Fall keine Beziehung.
Costa