3

C# 内でいくつかの機能パターンを学習/実験していますが、うまく説明できない問題にぶつかりました。それは簡単な答えだと思いますが(願っています)、私はそれを見るのに苦労しています。閉鎖などに関係している可能性が高く、すぐに使用できないため、答えが隠されています!

これが私の実験です: 関数デリゲート内から特定のクラスの真新しいインスタンスを返そうとしています..

public class Foo{
    string A { get; set ; }
}

static void Main( string[] args ){
    // the delegate...
    Func<Foo,bool> someFunc = o => {
        o = new Foo { A = "A new instance of o?" };
        return true;
    };

    Foo foo = null;   // was hoping to replace this via delegate
    var myFunc = someFunc;
    var result = myFunc( foo );

    if ( foo == null )
        Console.WriteLine( "foo unchanged :-(" );
    else
        Console.WriteLine( foo.A ); // hoping for 'A new instance of o?'

もちろん、出力に「foo 変更なし :-(」が表示されるだけです。null 以外の Foo インスタンスを渡し、プロパティ「A」を変更した (新しいインスタンスを返すのに対して) テストをわずかに変更しました。それは問題なく機能しました (つまり、オブジェクト参照を関数に渡すときに期待するのと同じように、既存のオブジェクトを変更できます)、デリゲートから新しいインスタンスを取得できないようです。

そう?コードで何か間違ったことをしているだけですか?これはまったくできますか?これが機能しない理由を理解したいと思います。

4

3 に答える 3

5

仮パラメータoはの値のコピーfooです。変異は変異oしませんfoo。次のように言うときと同じです。

int x = 1;
int y = x;
y = 2;

それは変わりませんxのエイリアスではなく、の値yコピーです。xx

あなたは問題を考えすぎています。ローカルを変更するデリゲートが必要な場合は、ローカルを変更するデリゲートを記述します。

Foo foo = null;   // was hoping to replace this via delegate
Action mutateFoo = () => { foo = new Foo() { A = "whatever"}; };
mutateFoo();
if ( foo == null )
    Console.WriteLine( "foo unchanged :-(" );
else
    Console.WriteLine( foo.A );

変数を変更するだけの場合は、変数を変更します。副作用を実行したいだけの場合は、デリゲートに何かを渡したり、デリゲートから渡したりする必要はありません。

機能的パターンを実験しているとあなたが言ったことに気づきました。関数型プログラミングは変数の変更を思いとどまらせます。

于 2013-03-16T14:46:20.310 に答える
4

Fooをラムダ式の戻り値として返すことができます。

Func<Foo> someFunc = o =>
{
    return new Foo { A = "A new instance of o?" };
};

または、Tuple<bool, Foo>本当に a を返す必要がある場合は、 a を返すことができますbool:

Func<Tuple<bool, Foo>> someFunc = o =>
{
    return Tuple.Create(true, new Foo { A = "A new instance of o?" });
};

または、それが本当に必要な場合は、パラメータFuncを使用して独自のカスタムのようなデリゲートを宣言できます。out

delegate TResult FuncOut<T, TResult>(out T arg);
FuncOut<Foo, bool> someFunc = (out Foo o) =>
{
     o = new Foo { A = "A new instance of o?" };
     return true;
};

Foo foo;
var result = someFunc(out foo);

しかし、私はそれをお勧めしません。

于 2013-03-16T14:23:09.293 に答える
2

オブジェクトの参照 (アドレス) をFooデリゲートに渡しています。そのアドレスはデリゲートのパラメーターに割り当てられますo(ローカル変数と見なします)。Fooデリゲートでオブジェクトを変更する場合、参照されるオブジェクトに移動し、そのアドレスにあるものを変更します。それがオブジェクトが変化する理由です。

しかし、デリゲートのローカル変数 (つまりパラメーター) に新しいアドレスを割り当てると、デリゲートFooに渡された元のオブジェクトのアドレスが失われます。割り当て後、ローカル変数は新しいFooオブジェクトのアドレスを保持するだけです。foo別のアドレスを保持している呼び出し元の変数には影響しません。

于 2013-03-16T14:24:58.353 に答える