15

これは、匿名メソッドからrefまたはoutパラメーターを使用してメソッドを呼び出すことの重複ではありません

匿名メソッド内でoutパラメーターが許可されないのはなぜか疑問に思います。refパラメーターを許可しないことは私には少し意味がありますが、outパラメーターはそれほど多くはありません。

これについてどう思いますか

4

4 に答える 4

31

いくつかの点で、これはだまされています。 Outパラメータはrefパラメータです。C#言語で使用される値には、単に追加の属性があります。refそれらを禁止する理由は、パラメーターとまったく同じです。

ここでの問題は、anonymousメソッド内でanonymousメソッドの外部で宣言された値を使用する効果に起因します。そうすることで、ラムダ内の値がキャプチャされ、必然的に、現在の関数の寿命を超えてその寿命が任意に延長されます。outこれは、有効期間が固定されているパラメータと は互換性がありません。

たとえば、outパラメータがスタック上のローカル変数を参照していると想像してください。ラムダは将来の任意の時点で実行できるため、そのスタックフレームが無効になったときに実行できます。では、outパラメータはどういう意味ですか?

于 2009-10-28T15:06:50.450 に答える
6

これは基本的に、匿名デリゲート/ラムダ式のパラメーターがキャプチャされた変数であり、キャプチャref/変数は内部で/フィールドoutを必要とするため、C#/CLRでは意味がないという事実と関係があります。また、これらのキーワードは実質的に同じであるため、両方をペアにすることに注意してください。refout

完全な説明が必要な場合は、EricLippertがブログでこの設計ポイントについて詳しく説明しています。(特に下部の段落を参照してください。)

于 2009-10-28T15:07:09.903 に答える
1

outrefパラメータの唯一の違いは、outパラメータに[out]トークンが適用されることです。CLRに関する限り、これらは同じです。

これを実装するには、コンパイラはサポートされていないref フィールドを生成する必要があります。

あなたがそれについて考えるならば、あなたは匿名のメソッドがoutパラメータを使用することを許可することは意味がないことに気付くでしょう。

次のコードは何になりますか?

static Func<object, object> Mess(out object param) {
    param = "Original";
    return i => param = i;
}
static Func<object, object> MessCaller() {
    object local;
    return Mess(out local);
}
static vouid Main() {
    Console.WriteLine(MessCaller()("New"));
    //The local variable that the lambda expression writes to doesn't exist anymore.
}
于 2009-10-28T15:12:36.913 に答える
1

エラー処理コードを開発しているときに、この難問に遭遇しました。ログに記録されるエラーメッセージへの参照(出力)を渡したかったのです。これにより、匿名のメソッドが複数のチェックを実行する機会が与えられ、それぞれが必要に応じてエラーメッセージを設定しました。

結局、動作が異なる匿名メソッドの新しいラッパーを作成することになりました。しかし、誰かにとって価値があると思ったのは、outパラメーターを持つプライベートメソッドを作成し、デリゲートを定義して、それをコードに使用させることができたということです。これが誰かを助け/刺激することを願っています。

    protected delegate void OutStringDelegate(int divider, out string errorText);
    protected void codeWrapper(int divider, OutStringDelegate del)
    {
        string ErrorMessage = "An Error Occurred.";

        try
        {
            del(divider, out ErrorMessage);
        }
        catch
        {
            LogError(ErrorMessage);
        }
    }
    public void UseWrapper(int input)
    {
        codeWrapper(input, codeToCall);
    }
    private int somePrivateValue = 0;
    private void codeToCall(int divider, out string errorMessage)
    {
        errorMessage = "Nice Error Message here!";
        somePrivateValue = 1 / divider; // call me with zero to cause error.
    }
    private void LogError(string msg)
    {
        Console.WriteLine(msg);
    }
于 2012-01-16T16:04:36.100 に答える