web-dev-qa-db-ja.com

C#でイベントを転送する

C#でイベントを転送するクラスを使用しています。コードのオーバーヘッドを少なくする方法があるのではないかと思っていました。

これが私がこれまでに持っているものの例です。

class A
{
   public event EventType EventA;
}

class B
{
   A m_A = new A();
   public event EventType EventB;

   public B()
   {
      m_A.EventA += OnEventA;
   }

   public void OnEventA()
   {
      if( EventB )
      {
         EventB();
      }
   }
}

クラスAは元のイベントを発生させます。クラスBはそれをEventB(本質的に同じイベント)として転送します。クラスAは他のモジュールから隠されているため、EventAに直接サブスクライブすることはできません。

私がやろうとしているのは、イベントを転送するためのクラスBのコードオーバーヘッドを減らすことです。通常、クラスBのイベントは実際には処理されません。また、いくつかの異なるイベントがあるため、多くのOnEventを作成する必要があります()イベントの転送にのみ役立つクラスBのメソッド。

なんらかの方法でEventAをEventBに自動的にリンクすることは可能ですか?

class B
{
   A m_A = new A();
   public event EventType EventB;

   public B()
   {
      m_A.EventA += EventB; // EventA automatically raises EventB.
   }
}

ところで、C#2.0コンパイラを使用しています。

46
user3891

絶対に:

class B
{
    private A m_a = new A();

    public event EventType EventB
    {
        add { m_a.EventA += value; }
        remove { m_a.EventA -= value; }
    }
}

つまり、EventBサブスクリプション/サブスクリプション解除コードは、サブスクリプション/サブスクリプション解除要求をEventAに渡すだけです。

ただし、これでは、EventBをサブスクライブしたサブスクライバーに対してイベントを発生させることはできませんjust。これは、誰かの住所をマスマーケティング会社に直接渡すようなものですが、元の方法は、マスマーケティング会社に自分で登録して、メールのコピーを送信するように依頼できるようにするようなものです。

80
Jon Skeet

IMO、元のコードは(多かれ少なかれ)正しいです。特に、正しいsenderを提供できます(これは、Bのイベントにサブスクライブしていると思う人にとってはBインスタンスである必要があります)。

イベントがサブスクライブされていない場合に実行時のオーバーヘッドを減らすためのいくつかのトリックがありますが、これはmoreコードを追加します:

class B {
   A m_A = new A();
   private EventType eventB;
   public event EventType EventB {
       add { // only subscribe when we have a subscriber ourselves
           bool first = eventB == null;
           eventB += value;
           if(first && eventB != null) m_A.EventA += OnEventB;
       }
       remove { // unsubscribe if we have no more subscribers
           eventB -= value;
           if(eventB == null) m_A.EventA -= OnEventB;
       }
   }

   protected void OnEventB(object sender, EventArgsType args) {
      eventB?.Invoke(this, args); // note "this", not "sender"

   }
}
11
Marc Gravell