非委托类型的事件 [英] Events of a non-delegate type

查看:159
本文介绍了非委托类型的事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实现了一个看起来像这样的界面的类:

I've implemented a class that looks like this interface:

[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类与MulticastDelegate类似。它可以调用它可以与另一个CustomEvent组合。而且CustomEvent可以从另一个CustomEvent中移除。

This CustomEvent class works much like a MulticastDelegate. It can invoked. It can be combined with another CustomEvent. And a CustomEvent can be removed from another CustomEvent.

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

Now, I want to declare a class like this:

class EventProvider
{
    public event CustomEvent MyEvent;

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

不幸的是,这段代码不能编译。出现编译器错误CS0066:

Unfortunately, this code does not compile. A Compiler Error CS0066 appears:

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

基本上,我需要的是具有添加删除访问者的属性,而不是获取设置。我认为唯一的方法是使用事件关键字。我知道一个明显的替代方法是声明添加和删除的两种方法,但是我也想避免这种情况。

Basically, what I need is a property that has add and remove accessors instead of get and set. I think the only way to have that is using the event keyword. I know that one obvious alternative is to declare two methods that would do the adding and removing, but I want to avoid that too.

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

Does anybody knows if there is a nice solution this problem? I wonder if there is any way to cheat the compiler to accept a non-delegate type as an event. A custom attribute, perhaps.

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

By the way, someone asked a similar question in experts-exchange.com. Since that site is not free, I can't see the responses. Here is the topic: http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21697455.html

推荐答案

如果您想要添加和删除 CustomEvent 事件中的对象(而不是常规代理)有两个选项:

If you want to be able to add and remove CustomEvent objects from the event (instead of regular delegates), there are two options:

从ICustomEvent中创建一个隐式转换到返回ICustomEvent(可能是Invoke)的实例方法的EventHandler(或其他一些代理),然后使用委托的Target属性获取 add 中的原始ICustomEvent, 删除访问者。

Make an implicit cast from ICustomEvent to EventHandler (or some other delegate) that returns an instance method of ICustomEvent (probably Invoke), then use the Target property of the delegate to get the original ICustomEvent in the add and remove accessors.

编辑:像这样:

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

Note that you'll still need to figure out how to add the first handler if it's a delegate (if the myEvent field is null)

创建类型为CustomEvent的可写属性,然后重载 + - 运算符,以允许 + = - =

Make a writable property of type CustomEvent, then overload the + and - operators to allow += and -= on the property.

编辑:为防止您的来电者覆盖事件,您可以在CustomEvent中公开以前的值(我假设它的工作方式类似于不可变堆栈),在setter中添加

EDIT: To prevent your callers from overwriting the event, you could expose the previous value in CustomEvent (I'm assuming it works like an immutable stack) and, in the setter, add

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

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

Note that when the last handler is removed, both value and myEvent.Previous will be null.

这篇关于非委托类型的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆