6

私は、同僚がコード内の奇妙な動作をデバッグするのを手伝っています。次のサンプルは、これを示しています。

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 ブロックが実際に呼び出されていることを確認しました。

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

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

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

の重複: try { return x; で実際に何が起こるか } 最後に { x = null; } 声明?

4

6 に答える 6

12

「最終的に」ブロックは値を returnValue に割り当てており、実際には値を返していません。finally ブロックが値を変更する前に「戻り」が既に発生しているため、「abc」が返されます。

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

于 2009-03-24T00:41:04.713 に答える
3

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

(これは内部で正確に機能するわけではありませんが、ここでのポイントには十分近いです)

于 2009-03-24T00:43:06.783 に答える
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";
    }
}

または、次のように、単純に return ステートメントを try ブロックの外に移動することもできます。

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 ブロックが常に戻り値をオーバーライドすることを考えると、これは疑わしい設計です。

于 2009-03-24T00:58:32.470 に答える
0

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

于 2009-03-24T00:42:49.030 に答える
0

何が起こっているのか本当に知りたい場合は、Reflectorをダウンロードしてインストールできます。これは、「バッグ オ トリック」に入れるのに最適なツールです。ボンネットの下で何が起こっているかを教えてくれます。

于 2009-03-24T00:44:15.283 に答える
0

推測では、return ステートメントがある時点で何が返されるか (文字列 "abc" への参照) を決定していると言えます。

したがって、finally later がその参照を別の文字列を参照するように設定しても、戻り値には影響しません。

于 2009-03-24T00:45:23.393 に答える