C#委托是否无法正常工作?

10

我有点新手,所以遇到了这个问题。问题是:为什么会调用func2?还有一个问题。如果我向委托添加一个函数,在这个函数中调用另一个委托,但是我希望在该函数调用此委托之前调用添加到第一个委托的每个其他函数,则是否有任何清洁解决方案(我真的不太关心getInvocationList)。

class Program
{
    delegate void voidEvent();
    voidEvent test;

    private void func1()
    {
        Console.Write("func1");
        test -= func2;
    }

    private void func2()
    {
        Console.WriteLine("func2");
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        p.test += p.func1;
        p.test += p.func2;
        p.test();
    }
}
2个回答

21
每次更改委托(+=或-=)时,您实际上正在创建整个调用列表的副本(将被调用的方法)。
因此,当您调用

p.test();

时,您将在该时间点调用调用列表中的每个委托。 在这些处理程序中更改它将更改下一次调用,但不会更改当前正在执行的调用。

3
是的。这就是为什么在多线程场景下,你可以写var func = p.test; if (func != null) { func(); }而不需要锁定任何东西的原因。因为funcp.test的副本,并且不关心对p.test所做的更改。 - Olivier Jacot-Descombes
但是在我调用test-= func2之后,调用getinvocationlist,我可以看到func2不再列表中了。所以您的意思是每个委托都有两个列表,一个正在被调用(并且无法访问),另一个将在下次被调用? - Yamcha
@user1316459,它实际上并没有两个列表。但是当您从字段调用委托时,您实际上正在说类似于:“立即获取字段的值,然后调用它”。这意味着您正在调用test的值的副本,而不是test本身。 - svick

7

Reed当然是正确的。这里有另一种思考方式。

class Number
{
    public static Number test;
    private int x;
    public Number(int x) { this.x = x; }
    public Number AddOne() 
    {
        return new Number(x + 1);
    }
    public void DoIt()
    {
        Console.WriteLine(x);
        test = test.AddOne();
        Console.WriteLine(x);
    }
    public static void Main()
    {
        test = new Number(1);
        test.DoIt(); 
    }
}

请问会打印出1、1还是1、2?为什么?

它应该会打印出1、1。当你这样说时:

test.DoIt();

那并不意味着。
        Console.WriteLine(test.x);
        test = test.AddOne();
        Console.WriteLine(test.x);

实际上,这意味着

Number temporary = test;
Console.WriteLine(temporary.x);
test = test.AddOne();
Console.WriteLine(temporary.x);

test的值的改变并不会影响到在DoIt中this的值

你正在做同样的事情。改变test的值并不会改变你要调用的函数列表;你请求调用特定的函数列表,并且这个列表将被调用。你不能在中途更改它,就像你不能在方法调用的中途更改this的含义一样。


1
您的“Number”定义中似乎缺少字段“x”。 - kvb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接