2009-03-24 11 views
6

Ich habe einem Kollegen geholfen, seltsames Verhalten in seinem Code zu debuggen. Das folgende Beispiel veranschaulicht das:Warum funktioniert mein Block nicht in C#?

static void Main(string[] args) 
{ 
    string answer = Sample(); 
    Console.WriteLine(answer); 
} 

public static string Sample() 
{ 
    string returnValue = "abc"; 

    try 
    { 
     return returnValue; 
    } 

    catch (Exception) 
    { 
     throw; 
    } 

    finally 
    { 
     returnValue = "def"; 
    } 
} 

Was gibt dieses Beispiel zurück?

Sie würden denken, dass wegen des finally Block, es "def" zurückgibt, aber tatsächlich, gibt es "abc" zurück? Ich bin durch den Code gegangen und habe bestätigt, dass der finally Block tatsächlich aufgerufen wird.

Die wirkliche Antwort ist, dass Sie Code wie diese überhaupt nicht schreiben sollten, aber ich bin immer noch verwirrt über das Verhalten.

Edit: Um den Fluss basierend auf einigen der Antworten zu klären.

Wenn Sie durch den Code gehen, wird das schließlich vor der Rückkehr ausgeführt.

Duplizieren von:What really happens in a try { return x; } finally { x = null; } statement?

Antwort

3

Ja, der Block finally wird ausgeführt, nachdem die Funktion zurückgegeben wurde, aber das spielt keine Rolle. Beachten Sie, dass der Rückgabewert als Wert übergeben wird. Daher wird eine neue temporäre Variable zum Zeitpunkt der Rückgabe erstellt, sodass der finally-Block den tatsächlichen Rückgabewert nicht beeinflusst.Wenn Sie das gewünschte Verhalten unterstützen möchten können Sie einen Out-Parameter verwenden, etwa so:

static void Main(string[] args) 
{ 
    string answer; 
    Sample(out answer); 
    Console.WriteLine(answer); 
} 

public static void Sample(out string answer) 
{ 

    try 
    { 
     answer = "abc"; 
     return; 
    } 

    catch (Exception) 
    { 
     throw; 
    } 

    finally 
    { 
     answer = "def"; 
    } 
} 

Oder könnten Sie einfach die Return-Anweisung bewegen außerhalb des Try-Block, etwa so:

static void Main(string[] args) 
{ 
    string answer = Sample(); 
    Console.WriteLine(answer); 
} 

public static string Sample() 
{ 
    string returnValue; 
    try 
    { 
     returnValue = "abc"; 
    } 

    catch (Exception) 
    { 
     throw; 
    } 

    finally 
    { 
     returnValue = "def"; 
    } 

    return returnValue; 
} 

Da der finally-Block jedoch immer den Rückgabewert überschreibt, ist dies ein fragwürdiger Entwurf.

12

Ihre „endlich“ Block einen Wert return zuweist und nicht tatsächlich einen Wert zurückgibt. Die "Rückgabe" ist bereits erfolgt, bevor der finally-Block den Wert ändert und daher "abc" zurückgegeben wird.

Während der Code ist verwirrend, als was Sie getan haben, macht keinen Sinn, was es tut, ist richtig.

+0

Dies ist falsch..Wenn die return-Anweisung in einem try-Block ist, wird der finally-Block, falls einer existiert, ausgeführt, bevor die Steuerung zur aufrufenden Methode zurückkehrt. – TStamper

+0

TStamper - der Rückgabewert wird im Versuch ausgewertet, während die Variable immer noch "abc" ist, dann wird schließlich die Variablenzuweisung ausgeführt und geändert, aber NICHT das, was bereits zwischengespeichert wurde, um zurückgegeben zu werden. – Chuck

+0

wahr, aber die Formulierung ist falsch.von dem, was er sagt, der Code nicht weiter in der Sample-Funktion ausführen – TStamper

0

Ich bin kein Experte, aber ich würde raten müssen, dass diese Funktion zurückkehrt, und dann schließlich aufruft. Da return returnValue bereits ausgeführt wurde, spielt es keine Rolle, welchen Wert returnValue im finally-Block annimmt. Dieses Verhalten macht Sinn, denn es ist soll den gesamten try-Block vor dem finally-Block ausführen, und der einzige Weg, den es tun kann, ist, wenn es von der Funktion wie sein soll zurückkommt.

3

Der finally Block führt effektiv nach die return Anweisung. Sie haben also bereits den alten Wert abc zurückgegeben, bevor Sie in Ihren finally Block gehen.

(dies ist nicht genau, wie unter der Haube arbeitet, aber es ist nah genug für den Punkt hier)

2

Gefunden this Link vor einiger Zeit, dass mit dieser Frage befaßt. Er macht sich die Mühe, den IL-Code zu zeigen, der genau nach Hause fährt.

0

Wenn Sie wirklich neugierig sind, was vor sich geht, können Sie Reflector herunterladen und installieren. Es ist ein fantastisches Werkzeug, um es in Ihre "Sack-Tricks" zu stecken. Es wird dir sagen, was unter der Motorhaube vor sich geht.

0

Bei einer Schätzung würde ich sagen, dass Sie bestimmen, was zurückgegeben wird (ein Verweis auf die Zeichenfolge "abc") an dem Punkt, an dem die return-Anweisung ist.

Die Tatsache, dass die später später setzt, dass Verweis auf eine andere Zeichenfolge verweist, hat keine Auswirkung auf den zurückgegebenen Wert.

Verwandte Themen