2009-03-24 12 views
6

私は同僚がコード内でいくつかの奇妙な動作をデバッグするのを手伝ってきました。次のサンプルはこれを示しています:finallyブロックが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"; 
    } 
} 

このサンプルは何を返しますか?

finallyブロックのために "def"を返しますが、実際には "abc"を返します。コードを踏んで、finallyブロックが実際に呼び出されたことを確認しました。

本当の答えは、最初にこのようなコードを書くべきではないということですが、私はまだその動作について困惑しています。

編集:いくつかの回答に基づいてフローを明確にする。

コードをステップ実行すると、returnの前にfinallyが最後に実行されます。

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

答えて

3

はい、finallyブロックは関数が返った後に実行されますが、これは問題ではありません。戻り値は値によって渡されるため、新しい一時変数が戻り時に作成されるため、finallyブロックは実際の戻り値に影響を与えません。あなたが希望の動作をサポートしたい場合、あなたはそうのように、outパラメータを使用することができます。

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

それとも、あなたは、単にそのように、tryブロックの外にreturn文を移動することができ:

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

をしかし、finallyブロックが常に戻り値をオーバーライドすることを考えると、これは疑わしい設計です。

12

あなたの「最終的に」ブロックはのreturnValueに値を代入して、実際に値を返しません。 finallyブロックが値を変更する前に "return"が既に発生しているため、 "abc"が返されます。

あなたがしたことが意味をなさないので、コードが混乱していますが、それは正しいものです。

+0

これは間違っています。return文がtryブロック内にある場合、finallyブロックが存在する場合は、制御が呼び出しメソッドに戻る前にfinallyブロックが実行されます。 – TStamper

+0

TStamper - 変数がまだ "abc"の間にtryの戻り値が評価された場合、最終的に実行され、変数代入は変更されますが、既にキャッシュされたものは返されません。 – Chuck

+0

trueですが、言い回しが間違っています。コードが何を述べているのかは、Sample関数で引き続き実行されません – TStamper

0

私は専門家ではありませんが、この関数が返すと推測する必要があります。そしてが最後に呼び出します。 return returnValueは既に実行されているので、finallyブロックでreturnValueがどの値を取るかは実際問題ではありません。 であるため、finallyブロックの前にtryブロック全体を実行することになっているため、このような動作は理にかなっています。

3

finallyブロックはreturnステートメントの後で有効に実行されます。したがって、あなたはすでにabcという古い値を返しています。最後にブロックに入る前に。

(フードの下でどのように動作するか、これは正確ではありませんが、それはここでのポイントのために十分に近いです)、この非常に疑問を扱ういくつかの時間前に

2

見つかりthisリンク。彼は、何が起こっているのかを家に追いやるILコードを表示するのに苦労します。

0

何が起こっているのか本当に興味があれば、Reflectorをダウンロードしてインストールできます。それはあなたの "バッグのトリック"に入れて素晴らしいツールです。それはボンネットの下で何が起こっているのかを伝えます。

0

私は、return文がある箇所で何が返されるか(文字列 "abc"への参照)を決定していると思います。

したがって、最後に後で参照が別の文字列を参照するように設定されても、返される値には影響しません。

関連する問題