3

パラメーターとして渡す C# デリゲートに混乱しています。

class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        Action holder = delegate{};
        //a.Attach1(holder); //nothing printed
        a.Attach2(ref holder);//print as expected

        holder();
    }
}

public class A
{
    private void P1()
    {
        Console.WriteLine("Inaccessible");
    }
    public void P2()
    {
        Console.WriteLine("Accessible");
    }
    public void Attach1(Action holder)
    {
        holder += P1;
        holder += P2;
    }
    public void Attach2(ref Action holder)
    {
        holder += P1;
        holder += P2;
    }
}

デリゲートは参照型ですが、Attach2 のように値型のように正しく機能するために、フォントに ref を付けて渡す必要があるのはなぜですか?

C++ の経験から、デリゲートは単なる関数ポインターであり、Attach1(Action ホルダー) は Attach1(Action* ホルダー) のようなものです。元のホルダーは「値」として渡されるため、割り当てられませんが、2 番目のケースでは、Attach2(ref Action holder) は Attach1(Action** holder) のようなもので、実際にポインタが渡されるため、正しく操作できます。しかし、なぜ .NET には指示やヒントがないのですか?

4

4 に答える 4

6

デリゲート インスタンスはimmutableであり、新しいデリゲート インスタンス+=への新しい割り当てであるためです。それは基本的に次のとおりです。

holder = (Action)Delegate.Combine(holder, P1);
holder = (Action)Delegate.Combine(holder, P2);

それを as として渡さないとref、新しい値はメソッドの外では見えません。

または、より簡単に言えば、string;を検討してください。astringも同様に不変で+=あり、代入です。今考えてみましょう:

public void Append(string s) {
    s += "[suffix]";
}
public void Append2(ref string s) {
    s += "[suffix]";
}

呼び出す場合:

string x = "abc";
Append(x);
Console.WriteLine(x);

わかりますabc。電話したら

string x = "abc";
Append2(ref x);
Console.WriteLine(x);

abc[suffix]-まったく同じ理由で。

于 2013-06-06T09:06:45.970 に答える
2
holder += P1;

この行は、効果的に新しいholderデリゲートを作成し、それを変数に割り当てます。既存のデリゲートは変更されません。

そう:

Action holder = delegate{};
a.Attach2(ref holder);

holder(); //<-- holder is no longer the delegate assigned two lines above

そしてもちろん、これを機能させるには を使用する必要があります。refそうしないと、内部の代入Attach2は実質的にローカル変数にしか影響しないためです。

于 2013-06-06T09:06:04.170 に答える
0

あなたはこれを試しているだけだと思います。通常、メンバーデリゲートに追加する関数を送信すると、メンバーは += によって返される新しいオブジェクトになります

public class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        a.Attach();
        a.doSomething();
    }
}

public class A
{
    public delegate void handler();
    public handler doSomething;
    private void P1()
    {
        Console.WriteLine("Inaccessible");
    }
    public void P2()
    {
        Console.WriteLine("Accessible");
    }
    public void Attach()
    {
        doSomething += P1;
        doSomething += P2;
    }
}
于 2013-06-07T08:25:09.677 に答える
0

MSDNに記載されているように

参照渡しの概念と参照型の概念を混同しないでください。2 つの概念は同じではありません。メソッド パラメーターは、値型か参照型かに関係なく、ref によって変更できます。参照によって渡される場合、値の型のボックス化はありません。

そのリンクの2番目の例を参照してください。質問について説明しています

于 2013-06-06T09:13:48.737 に答える