Ich möchte nur wissen, ob es sicher / gut ist, return
innerhalb eines using
Blocks anzurufen .
Zum Beispiel.
using(var scope = new TransactionScope())
{
// my core logic
return true; // if condition met else
return false;
scope.Complete();
}
Wir wissen, dass die zuletzt geschweifte Klammer abgesagt dispose()
wird. Aber was wird im obigen Fall sein, da return
die Kontrolle aus dem vorgegebenen Bereich (AFAIK) springt ...
- Wird ich
scope.Complete()
angerufen? - Und so für die
dispose()
Methode des Oszilloskops.
using{}
Bereich beendet ist, werden die relevanten Objekte entsorgt,return
"brechen" den Bereich - so werden die Objekte wie erwartet entsorgtscope.Complete()
Anruf niemals von dem von Ihnen bereitgestellten Beispiel getroffen wird, sodass Ihre Transaktion immer zurückgesetzt wird.using
'sdispose()
aufgerufen wird, wird bei der Rückkehr die Funktion, die diesenusing
Block enthält, zurückgegeben und alles, was dazu gehört, wird verwaist. Selbst wennscope
es nicht "von derusing
" entsorgt worden wäre (wie andere erklärten), wird es trotzdem entsorgt, weil die Funktion beendet wurde. Wenn C # einegoto
Aussage hätte - hast du schon gelacht? gut - dann, anstatt zurückzukehren, könnten Siegoto
nach der schließenden Klammer zurückkehren, ohne zurückzukehren. Logischerweisescope
wäre es immer noch möglich, aber Sie haben geradegoto
C # eingegeben, also wen interessiert die Logik in diesem Stadium?Antworten:
Es ist absolut sicher,
return
innerhalb Ihresusing
Blocks aufzurufen , da ein using-Block nur eintry/finally
Block ist.In Ihrem obigen Beispiel wird nach der Rückgabe
true
der Bereich entsorgt und der Wert zurückgegeben.return false
undscope.Complete()
wird nicht angerufen.Dispose
wird jedoch trotzdem aufgerufen, da es sich im finally-Block befindet.Ihr Code ist im Wesentlichen derselbe wie dieser (wenn dies das Verständnis erleichtert):
Bitte beachten Sie, dass Ihre Transaktion niemals festgeschrieben wird , da es keine Möglichkeit gibt
scope.Complete()
, die Transaktion festzuschreiben.quelle
Dispose
wird aufgerufen. Wenn der OP nicht weiß, was passiertusing
, weiß er wahrscheinlich nicht, was passiertfinally
.using
, zum Beispielusing (var callersVar = MyFunc(..)) ..
, anstelle der Verwendung innerhalb des Habens „MyFunc“ - ich den Anrufer bedeutet den Strom gegeben wird , und ist verantwortlich für die es über Schließungusing
oder explizit, oder (b) Lassen Sie MyFunc alle benötigten Informationen in andere Objekte extrahieren , die sicher zurückgegeben werden können. Dann können die zugrunde liegenden Datenobjekte oder Streams von Ihnen entsorgt werdenusing
. Sie sollten keinen undichten Code schreiben müssen.Das ist in Ordnung -
finally
Klauseln (das ist, was die schließende geschweifte Klammer derusing
Klausel unter der Haube tut) werden immer ausgeführt, wenn der Bereich verlassen wird, egal wie.Dies gilt jedoch nur für Anweisungen, die sich im finally-Block befinden (die bei Verwendung nicht explizit festgelegt werden können
using
). Daher würde in Ihrem Beispielscope.Complete()
niemals aufgerufen werden (ich erwarte jedoch, dass der Compiler Sie vor nicht erreichbarem Code warnt).quelle
Im Allgemeinen ist es ein guter Ansatz. Aber in Ihrem Fall, wenn Sie zurückkehren, bevor Sie das anrufen
scope.Complete()
, wird das TransactionScope nur in den Papierkorb verschoben. Kommt auf dein Design an.In diesem Beispiel wird Complete () nicht aufgerufen, und der Bereich wird entsorgt, vorausgesetzt, er erbt die IDisposable-Schnittstelle.
quelle
scope.Complete sollte unbedingt vorher aufgerufen werden
return
. Der Compiler zeigt eine Warnung an und dieser Code wird niemals aufgerufen.In Bezug auf sich
return
selbst - ja, es ist sicher, es inusing
Anweisung zu nennen . Die Verwendung wird übersetzt, um zu versuchen, endlich hinter den Kulissen zu blockieren, und schließlich ist Block sicher auszuführen.quelle
In dem von Ihnen angegebenen Beispiel liegt ein Problem vor.
scope.Complete()
wird nie genannt. Zweitens ist es keine gute Praxis,return
Anweisungen inusing
Anweisungen zu verwenden. Beachten Sie Folgendes:In diesem einfachen Beispiel geht es darum, dass; der Wert von
scope
ist null, wenn die Verwendung der Anweisung beendet ist.Es ist also besser, nicht mit Anweisungen nach innen zurückzukehren.
quelle
scope
wird nicht null sein - das einzige , was passieren wird ist , dassDispose()
auf diese Instanz geltend gemacht worden sind, und daher die Instanz sollte nicht mehr verwendet werden (aber es ist nicht null und es gibt nichts zu verhindern Sie , um zu versuchen und zu verwenden das entsorgte Objekt, obwohl dies tatsächlich eine unangemessene Verwendung eines Einwegobjekts ist).return scope
einen Verweis auf dieses Objekt zurück. Auf diese Weise verhindern Sie, dass der GC das entsorgte Objekt bereinigt, wenn Sie diese Referenz bei der Rückgabe zuweisen.Um sicherzustellen, dass das
scope.Complete()
aufgerufen wird, wickeln Sie es mit eintry/finally
. Dasdispose
wird aufgerufen, weil Sie es mit demusing
alternativentry/finally
Block umbrochen haben .quelle
In diesem Beispiel wird scope.Complete () niemals ausgeführt. Der Befehl return bereinigt jedoch alles, was auf dem Stapel zugewiesen ist. Der GC kümmert sich um alles, was nicht referenziert ist. Es gibt also kein Problem, es sei denn, es gibt ein Objekt, das vom GC nicht aufgenommen werden kann.
quelle