.NET委托作为参数问题传递

use*_*851 3 c# delegates

C#delegate因参数传递而感到困惑:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

委托是引用类型,为什么它仍然需要使用ref in font传递才能正常工作,如Attach2,类似于值类型?

从C++经验来看,委托只是一个函数指针,Attach1(Action holder)就像Attach1(Action*holder),原始持有者作为'value'传递,因此没有赋值,而在第二种情况下,Attach2(ref Action) holder)就像Attach1(Action**holder),指针实际传递,因此可以正确操作.但是为什么在.NET中没有任何迹象或暗示?

Mar*_*ell 6

因为委托实例是不可变的,并且+=委托实例的新赋值; 它基本上是:

holder = (Action)Delegate.Combine(holder, P1);
holder = (Action)Delegate.Combine(holder, P2);
Run Code Online (Sandbox Code Playgroud)

如果未将其传递,ref则不会在方法外看到新值.

或者用简单的术语来说 - 考虑一个string; a string同样是不可变的,+=是一种任务.现在考虑:

public void Append(string s) {
    s += "[suffix]";
}
public void Append2(ref string s) {
    s += "[suffix]";
}
Run Code Online (Sandbox Code Playgroud)

如果我们打电话:

string x = "abc";
Append(x);
Console.WriteLine(x);
Run Code Online (Sandbox Code Playgroud)

我们会看到abc.如果我们打电话

string x = "abc";
Append2(ref x);
Console.WriteLine(x);
Run Code Online (Sandbox Code Playgroud)

我们会看到abc[suffix]- 出于完全相同的原因.