What is the preferred way to bubble events?

后端 未结 3 1244
天命终不由人
天命终不由人 2020-12-30 02:25

I have three objects ObjectA has an ObjectB, ObjectB has an ObjectC. When ObjectC fires an event I need ObjectA to know about it, so this is what I\'ve done...



        
相关标签:
3条回答
  • 2020-12-30 03:16

    As other answers have stated, this is they way to do it.

    But you can go beyond!!! I've just implemented a good data structure on it, and it's like to give you a spin on it.

    Would be nice to have an automatic event bubbling? You could implement it using Reflection. My way is to define an Interface/Base class which declares an event (or a set of events). Then, the parameterless constructor of a base class will iterate other its properties/fields, and register automatically the members events for event propagation.

    There are some restriction on design, but if you have a deep structure and/or many (structured) events, it could be nice to have everything setup without any additional line of code.

    An initial base class could be:

    class BaseObject {
        public BaseObject() {
            FieldInfo[] fInfos = this.GetType().GetFields(...);
    
            foreach (FieldInfo fInfo in fInfos) {
                object fInfoValue = fInfo.GetValue(this, null);
                if (fInfoValue is BaseObject) {
                    BaseObject bMemberObject = (BaseObject)fInfoValue;
    
                    bMemberObject.MyEvent += new EventHandler(delegate() {
                        if (this.MyEvent != null)
                            MyEvent();
                    });
                }
        }
    
        public event MyEvent = null;
    
    }
    

    Of course, as already suggested, follow the event delegate delegate(object sender, EventArgs args) (I've used a simpler event for clarity). Naturally, is implicit that you classes A, B and C derives directly from BaseObject.

    Note that any logic could be implemented to bind structured events (you could be the nested event registration using the name and/or other reflected properties.

    0 讨论(0)
  • 2020-12-30 03:25

    Another approach, is to wrap it using add/remove:

    public class ObjectB
    {
        ObjectC objC;
    
        public ObjectB()
        {
            objC = new ObjectC();
        }
    
        public event EventFiredEventHandler EventFired
        {
            add { this.objC.EventFired += value; }
            remove { this.objC.EventFired -= value; }
        }
    }
    
    0 讨论(0)
  • 2020-12-30 03:25

    That's the way I do it. however I would recommend change your firing mechanism to this to make it thread safe

    protected void OnEventFired()
    {
        var tmpEvent = EventFired;
        if(tmpEvent != null)
        {
            tmpEvent();
        }
    }
    

    This keeps it from failing if EventFired becomes null between the null check and the firing.

    Also it is somewhat of a standard to follow the EventHandler pattern for your event delegates.

    protected virtual void OnEventFired(EventArgs e)
    {
        var tmpEvent = EventFired;
        if(tmpEvent != null)
        {
            tmpEvent(this, EventArgs.e);
        }
    }
    

    I was wrong about the threadsafe pattern, here is the full threadsafe event pattern

    /// <summary>
    /// Delegate backing the SomeEvent event.
    /// </summary>
    SomeEventHandler someEvent;
    
    /// <summary>
    /// Lock for SomeEvent delegate access.
    /// </summary>
    readonly object someEventLock = new object();
    
    /// <summary>
    /// Description for the event
    /// </summary>
    public event SomeEventHandler SomeEvent
    {
        add
        {
            lock (someEventLock)
            {
                someEvent += value;
            }
        }
        remove
        {
            lock (someEventLock)
            {
                someEvent -= value;
            }
        }
    }
    
    /// <summary>
    /// Raises the SomeEvent event
    /// </summary>
    protected virtual OnSomeEvent(EventArgs e)
    {
        SomeEventHandler handler;
        lock (someEventLock)
        {
            handler = someEvent;
        }
        if (handler != null)
        {
            handler (this, e);
        }
    }
    
    0 讨论(0)
提交回复
热议问题