冒泡事件的首选方式是什么?

发布于 2024-10-05 22:03:24 字数 1288 浏览 1 评论 0原文

我有三个对象ObjectA有一个ObjectB,ObjectB有一个ObjectC。当 ObjectC 触发一个事件时,我需要 ObjectA 知道它,所以这就是我所做的...

public delegate void EventFiredEventHandler();

public class ObjectA
{
    ObjectB objB;

    public ObjectA()
    {
        objB = new ObjectB();
        objB.EventFired += new EventFiredEventHandler(objB_EventFired);
    }

    private void objB_EventFired()
    {
        //Handle the event.
    }
}

public class ObjectB
{
    ObjectC objC;

    public ObjectB()
    {
        objC = new ObjectC();
        objC.EventFired += new EventFiredEventHandler(objC_EventFired);
        objC.FireEvent();
    }

    public event EventFiredEventHandler EventFired;
    protected void OnEventFired()
    {
        if(EventFired != null)
        {
            EventFired();
        }
    }

    private void objC_EventFired()
    {
            //objC fired an event, bubble it up.
        OnEventFired();
    }
}

public class ObjectC
{
    public ObjectC(){}

    public void FireEvent()
    {
        OnEventFired();
    }

    public event EventFiredEventHandler EventFired;
    protected void OnEventFired()
    {
        if(EventFired != null)
        {
            EventFired();
        }
    }
}

这是处理这个事件的正确方法,还是有更好的方法?我根本不想让 ObjectA 了解 ObjectC,只想知道它引发了一个事件。

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

public delegate void EventFiredEventHandler();

public class ObjectA
{
    ObjectB objB;

    public ObjectA()
    {
        objB = new ObjectB();
        objB.EventFired += new EventFiredEventHandler(objB_EventFired);
    }

    private void objB_EventFired()
    {
        //Handle the event.
    }
}

public class ObjectB
{
    ObjectC objC;

    public ObjectB()
    {
        objC = new ObjectC();
        objC.EventFired += new EventFiredEventHandler(objC_EventFired);
        objC.FireEvent();
    }

    public event EventFiredEventHandler EventFired;
    protected void OnEventFired()
    {
        if(EventFired != null)
        {
            EventFired();
        }
    }

    private void objC_EventFired()
    {
            //objC fired an event, bubble it up.
        OnEventFired();
    }
}

public class ObjectC
{
    public ObjectC(){}

    public void FireEvent()
    {
        OnEventFired();
    }

    public event EventFiredEventHandler EventFired;
    protected void OnEventFired()
    {
        if(EventFired != null)
        {
            EventFired();
        }
    }
}

Is this the proper way to handle this, or is there a better way? I don't want ObjectA to know about ObjectC at all, only that it raised an event.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

绻影浮沉 2024-10-12 22:03:24

另一种方法是使用添加/删除来包装它:

public class ObjectB
{
    ObjectC objC;

    public ObjectB()
    {
        objC = new ObjectC();
    }

    public event EventFiredEventHandler EventFired
    {
        add { this.objC.EventFired += value; }
        remove { this.objC.EventFired -= value; }
    }
}

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; }
    }
}
草莓酥 2024-10-12 22:03:24

我就是这样做的。但是我建议将您的触发机制更改为此,以使其线程安全

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


如果 EventFired 在空检查和触发之间变为空,这可以防止失败。

此外,遵循 EventHandler 模式 也是一种标准您的活动代表。

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

我对线程安全模式的看法是错误的,这是完整的线程安全事件模式

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

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);
    }
}
寂寞陪衬 2024-10-12 22:03:24

正如其他答案所说,这就是他们的做法。

但你可以超越!我刚刚在它上面实现了一个很好的数据结构,它就像给你一个旋转它。

如果有一个自动事件冒泡会很好吗?您可以使用反射来实现它。我的方法是定义一个接口/基类来声明一个事件(或一组事件)。然后,基类的无参数构造函数将迭代其其他属性/字段,并自动注册成员事件以进行事件传播。

设计有一些限制,但如果您有深层结构和/或许多(结构化)事件,那么无需任何额外的代码行即可完成所有设置可能会很好。

初始基类可以是:

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;

}

当然,正如已经建议的那样,遵循事件委托 delegate(object sender, EventArgs args) (为了清楚起见,我使用了一个更简单的事件)。
当然,您的类 ABC 是直接从 BaseObject 派生的。

请注意,可以实现任何逻辑来绑定结构化事件(您可以使用名称和/或其他反映的属性进行嵌套事件注册。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文