代码改变世界

为什么不能在Event所在Class外部判断Event是否存在?

2011-08-14 17:23  一一九九  阅读(455)  评论(0编辑  收藏  举报

        这个是因为在Delphi转C#的过程中,一个同事提出来的问题,想先判断一下某个Class是否存在某个Event,如果不存在则创建自己Handler, 如果存在则执行Class内部的委托。在写 XXClass.XXXEvent != null, 发现出现了一个错误,说是Event只能执行+, –操作。

       在StackOverFlow上找到了相关的解决方法:
http://stackoverflow.com/questions/1246116/in-c-why-cant-i-test-if-a-event-handler-is-null-anywhere-outside-of-the-class
     代码大体如下:

public class UseSomeEventBase { 
    public delegate void SomeEventHandler(object sender, EventArgs e); 
    public event SomeEventHandler SomeEvent; 
    protected void OnSomeEvent(EventArgs e) { 
        // CANONICAL WAY TO TEST EVENT. OF COURSE, THIS WORKS. 
        if (SomeEvent != null) SomeEvent(this, e); 
    } 
} 
public class UseSomeEvent : UseSomeEventBase { 
    public bool IsSomeEventHandlerNull() { 
        // "LEFT HAND SIDE" COMPILER ERROR 
        return SomeEvent == null; 
    } 
} 
class Program { 
    static void Main(string[] args) { 
        var useSomeEvent = new UseSomeEvent(); 
        useSomeEvent.SomeEvent +=new UseSomeEventBase.SomeEventHandler(FuncToHandle); 
        // "LEFT HAND SIDE" COMPILER ERROR 
        if (useSomeEvent.SomeEvent == null) { 
        } 
        var useSomeEventBase = new UseSomeEventBase(); 
        useSomeEventBase.SomeEvent += new UseSomeEventBase.SomeEventHandler(FuncToHandle); 
        // "LEFT HAND SIDE" COMPILER ERROR 
        if (useSomeEventBase.SomeEvent == null) { 
        } 
    } 
    static void FuncToHandle(object sender, EventArgs e) { } 
} 

这里需要重点说明的是:提出这个问题的人不仅仅是在类的外部进行了判断,在继承类中也进行了判断,结果也是不行的。

给出来的解释也很直接明了

21 down vote accepted

An event is really just an "add" operation and a "remove" operation. You can't get the value, you can't set the value, you can't call it - you can just subscribe a handler for the event (add) or unsubscribe one (remove). This is fine - it's encapsulation, plain and simple. It's up to the publisher to implement add/remove appropriately, but unless the publisher chooses to make the details available, subscribers can't modify or access the implementation-specific parts.

Field-like events in C# (where you don't specify the add/remove bits) hide this - they create a variable of a delegate type and an event. The event's add/remove implementations just use the variable to keep track of the subscribers.

Inside the class you refer to the variable (so you can get the currently subscribed delegates, execute them etc) and outside the class you refer to the event itself (so only have add/remove abilities).

The alternative to field-like events is where you explicitly implement the add/remove yourself, e.g.

private EventHandler clickHandler; // Normal private field

public event EventHandler Click
{
    add
    {
        Console.WriteLine("New subscriber");
        clickHandler += value;
    }
    remove
    {
        Console.WriteLine("Lost a subscriber");
        clickHandler -= value;
    }
}

See my article on events for more information.

Of course the event publisher can also make more information available - you could write a property like ClickHandlers to return the current multi-cast delegate, or HasClickHandlersto return whether there are any or not. That's not part of the core event model though.

 

   大体意思是Event是Field-like的方法列表,只是提供了Add,Remove两种方法,没有其他的处理方式,如果想自己加入当前有多少事件或者订阅的话,需要自己声明一个delegate,然后外部释放出来一部分方法,比如hasEvent之类的。

     关键的一句话:“Remember an event is essentially a property, but for method calls, it isn't really an object itself

不过按照给出来的答案,此时如果你重写Event的触发方法的时候,仍然会报错,此时在本类中不能够调用Event,只能自己手动的写。

        public event EventIsNULL Click
        {
            add
            {
                Console.WriteLine("New subscriber");
                clickHandler += value;
            }
            remove
            {
                Console.WriteLine("Lost a subscriber");
                clickHandler -= value;
            }
        }
        public void OnClick(EventArgs e)
        {
            if (this.OnClick != null)
            {
                OnClick();
                Console.WriteLine("sdfsdfsd");
            }
        }
如上在方法OnClick中此时不能够调用this.OnClick方法的,也不能调用Onclick方法。