1

我正在尝试编写 的扩展方法EventHandler,如下所示:

public static class MyExtensions
{
    public static void Add(this EventHandler handler, EventHandler next)
    {
        //Do something
    }
}

它适用于我的活动,例如:

public event EventHandler MyEvent

我可以毫无问题地使用我的扩展程序:

MyEvent.Add((x, y) => { /* do something */ });

但是当我想将它应用到 TextBox 的 Click 事件时,我得到一个编译错误:

错误 CS0079:

+=事件 System.Windows.Forms.TextBoxBase.Click 只能出现在或的左侧-=

令我困惑的是, Click 事件看起来与 没有任何不同MyEvent,那么为什么它确实有约束?

4

2 回答 2

4

如果从定义的同一个类中Add调用该方法,它可能会正常工作。MyEvent

但是,该Click方法是在与您调用的地方不同的类Add中定义的。这就是为什么它不起作用。

.NET 框架不允许在定义它的类之外直接修改事件,否则一些 rouge 代码可能会删除任何类的所有事件处理程序。

这是我能想到的最好的扩展方法,可以帮助你做你想做的事:

public static Action Add<TDelegate>(
    this TDelegate handler, 
    Action<TDelegate> addHandler, 
    Action<TDelegate> removeHandler)
{
    addHandler(handler);
    return () => removeHandler(handler);
} 

你可以像这样使用它:

var bar = new Bar();

EventHandler handler = (s, e) =>
{
    Console.WriteLine("MyEvent!");
};

var cleanup = handler.Add(h => bar.MyEvent +=h, h => bar.MyEvent -=h);
bar.Raise();
bar.Raise();
cleanup();

cleanup操作用于在不需要时删除事件处理程序。

为简单起见,我省略了所有必需的空检查代码。您必须将它们放在适当的位置。

于 2012-10-07T11:53:57.420 回答
1

两者是有区别的。一个简单的例子可以证明:

private EventHandler foodel;
public event EventHandler foo {
    add { foodel += value; }
    remove { foodel -= value; }
}
public event EventHandler bar;

...
foo.Add((s, e) => { });   // CS0079
bar.Add((s, e) => { });   // No error

删除访问器,代码编译干净。

我要冒昧地说您无意中利用了编译器错误。它也应该拒绝在没有访问器的情况下声明的事件上使用扩展方法。微软修复该错误的几率非常低,这已经存在太久了。然而,最好的解决方法是删除扩展方法。

于 2012-10-07T12:56:36.533 回答