C# 事件和类方法

6
我想知道如果我这样做会怎么样:

我在想如果我做了这样的事:

class A
{
    public MethodA()
    {
    }
    public MethodB()
    {
        ExternalObject.Click += this.MethodA;
    }
    public MethodC()
    {
        ExternalObject.Click -= this.MethodA;
    }
}

A a = new A();
a.MethodB();
a.MethodC();

这会起作用吗?我指的是 - MethodA 会被取消订阅 ExternalObject.Click 事件吗?

还有其他相关的问题:

当使用实例方法而不是委托实例时,背后发生了什么?(就像上面那样)

这会导致委托的隐式创建吗?

-= 运算符如何在委托之间执行比较 - 是通过引用还是发生了更复杂的事情?

2个回答

8
是的,它会按照你想要的方式工作。
比较并非通过引用进行,而是通过值进行,这意味着只要不同委托指向相同对象上的相同方法,您就可以取消订阅一个不同的委托。
换句话说,以下代码也可以正常工作:
var delegate1 = new ExternalObjectClickEventHandler(MethodA);
var delegate2 = new ExternalObjectClickEventHandler(MethodA);
ExternalObject.Click += delegate1;
ExternalObject.Click -= delegate2;

匿名方法有所不同,您不能这样做:
public MethodB()
{
    ExternalObject.Click += () => { return 10; };
}

public MethodC()
{
    ExternalObject.Click -= () => { return 10; };
}

虽然这些方法包含相同的代码,但它们被认为是不同的,因此这不起作用,也就是说,在MethodB中添加的委托无法通过MethodC取消订阅。

要解决这个问题,你需要在调用之间存储委托,像这样:

private ExternalObjectClickEventHandler _ClickEventHandler;
public MethodB()
{
    _ClickEventHandler = () => { return 10; };
    ExternalObject.Click += _ClickEventHandler;
}

public MethodC()
{
    ExternalObject.Click -= _ClickEventHandler;
}

但是你展示的代码将会起作用。

至于你的问题背后发生了什么,以下两行代码在生成代码方面是相同的:

ExternalObject.Click += MethodA;
ExternalObject.Click += new ExternalObjectClickEventHandler(MethodA);

第二段代码是根据第一段生成的(假定事件类型如所示)。
第一个语法被添加为“语法糖”,编译器会将其转换为您编写了第二个语法,但只有在编译器可以100%确定正确类型的情况下才会发生。我曾看到过一些情况(我现在记不起来了)需要使用完全限定的语法,因为编译器无法理解你的意思。特别地,在方法重载和泛型方面可能会使编译器混淆。

感谢您提供详尽的答案。 - kubal5003

3

是的,MethodA 将被取消订阅。

关于第二个问题,我不是100%确定,但我认为 = this.MethodA 会在后台转换为委托。


+1. this.MethodA 将被隐式转换为委托。 - kol

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