我实现了一个类似于此接口的类:

[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);
}

这个customevent类的工作方式非常类似于multicast委托。它可以被调用。它可以与另一个customevent组合。并且可以从另一个customevent中删除customevent。
现在,我想声明这样一个类:
class EventProvider
{
    public event CustomEvent MyEvent;

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

不幸的是,这段代码无法编译。出现编译器错误CS0066:
“eventprovider.myevent”:事件必须是委托类型
基本上,我需要的是一个有add和remove访问器的属性,而不是get和set。我认为唯一的方法就是使用event关键字。我知道一个明显的选择是声明两个方法来完成添加和删除,但我也希望避免这样做。
有人知道这个问题有没有好的解决办法吗?我想知道是否有办法欺骗编译器接受非委托类型作为事件。也许是一个自定义属性。
顺便说一下,有人在experts-exchange.com上问了一个类似的问题。因为那个网站不是免费的,我看不到回复。主题如下:http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21697455.html

最佳答案

如果希望能够从事件中添加和移除CustomEvent对象(而不是常规委托),有两个选项:
从icustomevent隐式转换为eventhandler(或其他委托),返回icustomevent的实例方法(可能是invoke),然后使用委托的target属性在addremove访问器中获取原始icustomevent。
编辑:如下所示:

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
    }
}

请注意,如果第一个处理程序是委托的话(如果myEvent字段是null,那么您仍然需要弄清楚如何添加它)
创建一个customevent类型的可写属性,然后重载+-运算符以允许属性上的+=-=
编辑:为了防止调用方重写事件,可以在customevent中公开前一个值(我假设它的工作方式类似于immutable stack),并在setter中添加
if (myEvent.Previous != value && value.Previous != myEvent)
    throw new ArgumentException("You cannot reset a CustomEvent", "value");

注意,当删除最后一个处理程序时,valuemyEvent.Previous都将是null

07-27 20:31