非委托类型的事件

jpb*_*chi 5 .net c# events delegates

我已经实现了一个看起来像这个接口的类:

[ImmutableObject(true)]
public interface ICustomEvent
{
    void Invoke(object sender, EventArgs e);

    ICustomEvent Combine(EventHandler handler);
    ICustomEvent Remove(EventHandler handler);

    ICustomEvent Combine(ICustomEvent other);
    ICustomEvent Remove(ICustomEvent other);
}
Run Code Online (Sandbox Code Playgroud)

此CustomEvent类的工作方式与MulticastDelegate非常相似.它可以调用.它可以与另一个CustomEvent结合使用.并且可以从另一个CustomEvent中删除CustomEvent.

现在,我想声明一个这样的类:

class EventProvider
{
    public event CustomEvent MyEvent;

    private void OnMyEvent()
    {
        var myEvent = this.MyEvent;
        if (myEvent != null) myEvent.Invoke(this, EventArgs.Empty);
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这段代码无法编译.出现编译器错误CS0066:

'EventProvider.MyEvent':事件必须是委托类型

基本上,我需要的是一个添加删除访问器而不是getset的属性.我认为唯一的方法就是使用event关键字.我知道一个明显的替代方案是声明两个可以进行添加和删除的方法,但我也想避免这种情况.

有谁知道这个问题是否有一个很好的解决方案?我想知道是否有任何方法可以欺骗编译器接受非委托类型作为事件.也许是自定义属性.

顺便说一句,有人在expert-exchange.com上提出了类似的问题.由于该网站不是免费的,我看不到回复.以下是主题:http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21697455.html

SLa*_*aks 5

试试这个:

CustomEvent myEvent

public event EventHandler MyEvent {
    add { myEvent = myEvent.Combine(value); }
    remove {myEvent = myEvent.Remove(value); }
}
Run Code Online (Sandbox Code Playgroud)

您可以向其添加和删除正常的EventHandler委托,它将执行addremove访问器.


编辑:你可以在这里找到一个弱事件实现.
2 编辑:或者在这里.


SLa*_*aks 2

如果您希望能够CustomEvent在事件中添加和删除对象(而不是常规委托),有两个选项:

add进行从 ICustomEvent 到 EventHandler(或其他某个委托)的隐式转换,该委托返回 ICustomEvent 的实例方法(可能是 Invoke),然后使用委托的 Target 属性在和访问器中获取原始 ICustomEvent remove

编辑:像这样:

CustomEvent myEvent;
public event EventHandler MyEvent {
    add {
        if (value == null) throw new ArgumentNullException("value");
        var customHandler = value.Target as ICustomEvent;

        if (customHandler != null)
            myEvent = myEvent.Combine(customHandler);
        else
            myEvent = myEvent.Combine(value);   //An ordinary delegate
    }
    remove {
        //Similar code
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您仍然需要弄清楚如何添加第一个处理程序(如果它是委托)(如果该myEvent字段是null


创建一个 CustomEvent 类型的可写属性,然后重载+and-运算符以允许在该属性上使用+=and 。-=

编辑:为了防止调用者覆盖事件,您可以公开 CustomEvent 中的先前值(我假设它像不可变堆栈一样工作),并在设置器中添加

if (myEvent.Previous != value && value.Previous != myEvent)
    throw new ArgumentException("You cannot reset a CustomEvent", "value");
Run Code Online (Sandbox Code Playgroud)

请注意,当最后一个处理程序被删除时, 和valuemyEvent.Previous将为null