22

ObjectA には ObjectB があり、ObjectB には ObjectC がある 3 つのオブジェクトがあります。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 についてまったく知られたくありません。イベントを発生させただけです。

4

3 に答える 3

21

別のアプローチは、追加/削除を使用してラップすることです。

public class ObjectB
{
    ObjectC objC;

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

    public event EventFiredEventHandler EventFired
    {
        add { this.objC.EventFired += value; }
        remove { this.objC.EventFired -= value; }
    }
}
于 2010-12-03T19:54:33.343 に答える
4

それが私のやり方です。ただし、スレッドセーフにするために、発射メカニズムをこれに変更することをお勧めします

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

これにより、null チェックと発火の間に EventFired が null になった場合に失敗しなくなります。

また、イベント デリゲートの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);
    }
}
于 2010-12-03T19:43:03.450 に答える
1

他の回答が述べているように、これが彼らのやり方です。

しかし、あなたはそれを超えることができます!!! 私はそれに良いデータ構造を実装したところです。それを試してみたいと思います。

自動イベントバブリングがあればいいのに?リフレクションを使用して実装できます。私のやり方は、イベント (または一連のイベント) を宣言する Interface/Base クラスを定義することです。次に、基本クラスのパラメーターなしのコンストラクターは、他のプロパティ/フィールドを反復処理し、イベント伝達のためにメンバー イベントを自動的に登録します。

設計にはいくつかの制限がありますが、深い構造および/または多くの (構造化された) イベントがある場合は、追加のコード行なしですべてをセットアップするとよいでしょう。

最初の基本クラスは次のようになります。

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)に従います(わかりやすくするために、より単純なイベントを使用しました)。当然、クラスAB、およびCがBaseObjectから直接派生することは暗黙的です。

構造化されたイベントをバインドするために、任意のロジックを実装できることに注意してください (名前やその他の反映されたプロパティを使用して、ネストされたイベント登録を行うことができます。

于 2010-12-03T20:14:40.807 に答える