c# - 使用 = 而不是 += 订阅事件

标签 c# events

订阅事件有什么问题吗

MyPopup.CustomPopupPlacementCallback = popupFixCentered;

而不是:

MyPopup.CustomPopupPlacementCallback += popupFixCentered;

例如,如果我要从另一种方法更改为不同的回调,我想确保我只订阅了一个回调,而无需 -= 正确的回调。

最佳答案

嗯,看来你没有尝试过。如果这样做,您将收到以下编译错误:

The event 'XXX' can only appear on the left hand side of += or -= (except when used from within the type 'YourClass')

错误非常明显:您只能在事件上使用 +=-= 运算符。

如果您尝试从定义事件的类中分配给事件,那么它将“起作用”。但在这种情况下它似乎能够分配给事件的原因是因为它实际上没有访问该事件。它正在访问一个自动生成的私有(private)委托(delegate)实例,您可能没有意识到该实例实际上存在。

引用自Chris Burrows' article关于主题:

outside of the class or struct that defines a field-like event E, binding to the name E resolves to the event itself, on which the only legal operation is calling an accessor; inside the class or struct that defines a field-like event E, binding to the name E resolves to the private delegate field.

要理解这一点,您需要在定义事件时将其可视化,例如:

public event EventHandler MyEvent;

...你没有看到的是,它实际上被翻译成这样的东西(我从 Jon Skeet's article on events and delegates 复制这个。另请注意,它被翻译成的确切代码在C# 版本,所以可能有点不同,但总体思路是相同的):

private EventHandler _myEvent;

public event EventHandler MyEvent
{
    add
    {
        lock (this)
        {
            _myEvent += value;
        }
    }
    remove
    {
        lock (this)
        {
            _myEvent -= value;
        }
    }        
}

因此,当您从类的外部访问MyEvent时,您只能调用add通过 +=-= 运算符删除 方法。

但是从类中,访问MyEvent意味着不同的事情。它实际上成为对您看不到的私有(private) _myEvent 委托(delegate)变量的引用,但它确实存在。因为这是委托(delegate)类型,所以您可以对其使用赋值 (=) 运算符。


因此,为了实现您想要的目的,您可以在定义事件的同一类中定义一个公共(public)方法,并使用该方法来设置新的事件处理程序。

类似这样的事情:

public class MyClass
{
    public event EventHandler MyEvent;

    public void setSingleEventHandler(EventHandler eventHandler)
    {
        this.MyEvent = eventHandler;
    }
}

但是如果您打算这样做,那么它就违背了 event 类型的目的。如果您只想在任何给定时间最多调用一个事件处理程序,那么以这种方式定义它(不使用 event 关键字)更有意义:

public class MyClass
{
    public EventHandler MyEvent { get; set; }
}

引用文献

乔恩·斯基特文章:Delegates and Events

Chris Burrows 文章:(另请查看该系列的其余部分):Events get a little overhaul in C# 4, Part II: Semantic Changes and +=/-=

关于c# - 使用 = 而不是 += 订阅事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31226717/

相关文章:

BackgroundWorker 的 C# 问题

python - 用于水平边缘滚动(在 Linux 中)的 Tkinter 事件是什么?

C#/.NET - WinForms - 实例化一个表单而不显示它

c - SDL 左控件 keydown 事件在释放键时触发

c# - 检查特定表单字段是否有效

c# - int、string、array、list、object 等的公认命名约定是什么

c# - 当 ListView 被禁用时,在 ListView 中启用分页。 ASP.NET C#

java - 如何解决 Stripe xamarin 绑定(bind)错误? (CS0103 名称 'Start' 在当前上下文中不存在)

events - 停止空格键滚动页面

php - 如何通过php更改mysql分隔符