2

単純なイベントバスを実装しようとしています

私はこのように始めました:

public class RegistrationData
{
    public object RegisteredObject { get; set; }
    public Type eventType { get; set; }
    public EventHandler MethodToInvoke;
}
public class EventBus
{
    private static EventBus instance;
    private static readonly object lockObject = new object();
    private static List<RegistrationData> registrationList;

    private EventBus()
    {
    }

    public static EventBus Instance
    {
        get
        {
            lock (lockObject)
            {
                registrationList = new List<RegistrationData>();
                return instance ?? new EventBus();
            }
        }
    }

    public void Subscribe(RegistrationData registrationData)
    {
        if(!registrationList.Contains(registrationData)) registrationList.Add(registrationData);
    }

    public void Unsubscribe(object objectToUnregister, Type eventType)
    {
        foreach(RegistrationData data in registrationList)
            if (data.RegisteredObject == objectToUnregister && data.eventType == eventType) registrationList.Remove(data);
    }

    public void UnregisterAllMessages(object objectToUnregister)
    {
        foreach(RegistrationData data in registrationList)
            if(data.RegisteredObject == objectToUnregister) registrationList.Remove(data);
    }

    public void PublishEvent(object sender, EventArgs eventArgs)
    {
        foreach (RegistrationData data in registrationList)
            if (EventArgs is typeof(data.Type)) data.MethodToInvoke(sender, eventArgs);
    }
}

しかし、PublishEventメソッドに問題があります。イベント引数のタイプを判別できません。そして、私はこれがすべてかなり間違っているのではないかと疑っています。

誰かが私が間違っていることを指摘できますか、これをどのように実装する必要がありますか?または、イベントバスが一般的にどのように実装されているか、または自分で実装してそれに時間を費やす代わりに使用できるフレームワーク。

4

3 に答える 3

2

イベントバスを定義することから始めるべきだと思います。イベントバスと、イベントを起動およびシンクするための組み込みの.NETメカニズムの違いは何だと思いますか?これまでのところ、.NETイベントに相当するものを実装しているように見えます。.NETは本質的にイベント処理をサポートしているため、.NETがすでに提供している以上のものが必要ない場合は、イベントバスは必要ありません。

class Program
{
  static void Main(string[] args)
  {
     BusinessObject1 bo = new BusinessObject1("First Value");
     // Subscribe
     bo.Publish += new BusinessObject.PublishObject(bo_Publish);
     bo.Update("Second Value");
     // UnSubscribe
     bo.Publish -= new BusinessObject.PublishObject(bo_Publish);
     bo.Update("Third Value");
     // Subscribe multiple
     bo.Publish += new BusinessObject.PublishObject(bo_Publish);
     bo.Publish += new BusinessObject.PublishObject(bo_Publish2);
     bo.Update("Fourth Value");
     // UnregisterAllMessages
     bo.UnsubcribeAll();
     bo.Update("Fifth Value");
  }

  static void bo_Publish(BusinessObject sender, EventArgs args)
  {
     if (sender is BusinessObject1)
     {
        BusinessObject1 bo1 = (BusinessObject1)sender;
        BusinessObject1.PublishBusinessObject1EventArgs args1 =
           (BusinessObject1.PublishBusinessObject1EventArgs)args;
        Console.WriteLine("Updated {0} to {1}", args1.oldValue, bo1.Value);
     }
  }

  static void bo_Publish2(BusinessObject sender, EventArgs args)
  {
     if (sender is BusinessObject1)
     {
        BusinessObject1 bo1 = (BusinessObject1)sender;
        BusinessObject1.PublishBusinessObject1EventArgs args1 =
           (BusinessObject1.PublishBusinessObject1EventArgs)args;
        Console.WriteLine("Second handler detected updated of {0} to {1}", args1.oldValue, bo1.Value);
     }
  }
}

abstract class BusinessObject
{
  public delegate void PublishObject(BusinessObject sender, EventArgs args);
  public event PublishObject Publish;
  // PublishEvent
  protected void Update(EventArgs args)
  {
     if (Publish != null)
        Publish(this, args);
  }
  public void UnsubcribeAll()
  {
     Publish = null;
  }
}

class BusinessObject1 : BusinessObject
{
  public class PublishBusinessObject1EventArgs : EventArgs
  {
     public string oldValue;
     public PublishBusinessObject1EventArgs(string oldValue)
     {
        this.oldValue = oldValue;
     }
  }

  public delegate void PublishBusinessObject1(BusinessObject1 sender, PublishBusinessObject1EventArgs args);

  public string Value {get; private set;}

  public BusinessObject1(string value)
  {
     this.Value = value;
  }

  public void Update(string newValue)
  {
     PublishBusinessObject1EventArgs args = new PublishBusinessObject1EventArgs(Value);
     Value = newValue;
     base.Update(args);
  }
}

編集: ビジネスオブジェクトが共通の基本クラスから継承する必要がない場合(コメントで提案したように)、EventBusがより独立して立つようにいくつかの変更を加えることができますが、それでも再実行する必要はありません。 -これを行うために、すべてのイベント登録フレームワークを実装します。

class Program
{
  static void Main(string[] args)
  {
     BusinessObject1 bo = new BusinessObject1("First Value");
     // Subscribe
     EventBus.Publish += new EventBus.PublishObject(EventBus_Publish);
     bo.Update("Second Value");
     // UnSubscribe
     EventBus.Publish -= new EventBus.PublishObject(EventBus_Publish);
     bo.Update("Third Value");
     // Subscribe multiple
     EventBus.Publish += new EventBus.PublishObject(EventBus_Publish);
     EventBus.Publish += new EventBus.PublishObject(EventBus_Publish2);
     bo.Update("Fourth Value");
     // UnregisterAllMessages
     EventBus.UnsubcribeAll();
     bo.Update("Fifth Value");
  }

  static void EventBus_Publish(object sender, EventArgs args)
  {
     if (sender is BusinessObject1)
     {
        BusinessObject1 bo1 = (BusinessObject1)sender;
        BusinessObject1.PublishBusinessObject1EventArgs args1 =
           (BusinessObject1.PublishBusinessObject1EventArgs)args;
        Console.WriteLine("Updated {0} to {1}", args1.oldValue, bo1.Value);
     }
  }

  static void EventBus_Publish2(object sender, EventArgs args)
  {
     if (sender is BusinessObject1)
     {
        BusinessObject1 bo1 = (BusinessObject1)sender;
        BusinessObject1.PublishBusinessObject1EventArgs args1 =
           (BusinessObject1.PublishBusinessObject1EventArgs)args;
        Console.WriteLine("Second handler detected updated of {0} to {1}", args1.oldValue, bo1.Value);
     }
  }
}

static class EventBus
{
  public delegate void PublishObject(object sender, EventArgs args);
  public static event PublishObject Publish;
  // PublishEvent
  public static void Update(object sender, EventArgs args)
  {
     if (Publish != null)
        Publish(sender, args);
  }
  public static void UnsubcribeAll()
  {
     Publish = null;
  }
}

class BusinessObject1
{
  public class PublishBusinessObject1EventArgs : EventArgs
  {
     public string oldValue;
     public PublishBusinessObject1EventArgs(string oldValue)
     {
        this.oldValue = oldValue;
     }
  }

  public delegate void PublishBusinessObject1(BusinessObject1 sender, PublishBusinessObject1EventArgs args);

  public string Value { get; private set; }

  public BusinessObject1(string value)
  {
     this.Value = value;
  }

  public void Update(string newValue)
  {
     PublishBusinessObject1EventArgs args = new PublishBusinessObject1EventArgs(Value);
     Value = newValue;
     EventBus.Update(this, args);
  }
}

編集2:ちなみに、サブスクリプションプロセスをより細かく制御したい場合は、http://msdn.microsoft.com/en-us/library/bb882534で説明されているように、カスタムイベントアクセサーを定義することで、そこでもより細かく制御できます。 aspx

static class EventBus
{
  public delegate void PublishObject(object sender, EventArgs args);
  private static List<PublishObject> subscribers = new List<PublishObject>();
  public static event PublishObject Publish
  {
     add
     {
        subscribers.Add(value);
        Console.WriteLine("Added subscriber {0}.{1}", value.Method.DeclaringType.Name, value.Method.Name);
     }
     remove
     {
        bool result = subscribers.Remove(value);
        Console.WriteLine("Removed subscriber {0}.{1} ({2})", value.Method.DeclaringType.Name, value.Method.Name, result ? "success" : "failure");
     }
  }
  // PublishEvent
  public static void Update(object sender, EventArgs args)
  {
     foreach (PublishObject p in subscribers)
     {
        Console.WriteLine("Publishing to {0}.{1}", p.Method.DeclaringType.Name, p.Method.Name);
        p.Invoke(sender, args);
     }
  }
  public static void UnsubcribeAll()
  {
     subscribers.Clear();
  }
}
于 2011-07-09T15:53:48.503 に答える
2

ええと、イベントバスがどのように動作するべきかよくわかりません。自分がどこに向かっているのかを知るだけでなく、他の人がどのように問題を実装したかを調べることも役に立ちます。

  • caliburn.microプロジェクトには、現実的なイベント アグリゲーターがあります。
  • イベント アグリゲーターが必要な場合は、 MemBusを使用するのが好きです。これは、MemBusを自分で作成したことと、その点ですべてのニーズをカバーしているためです。カリバーンのものより複雑ですが、より多くの機能があります
于 2011-07-09T15:03:16.713 に答える
1

最初の提案として、これをシングルトンとして実装しようとしているように見えます。そうでなければ、

private static EventBus instance;

に良い?しかし、プライベート インスタンス メンバーがどこにも割り当てられることはありません。これは、修正する必要があることの 1 つです。参考までに、シングルトンのさまざまな実装に関する非常に優れた記事を次に示します。.net4 にアクセスできる場合は、このLazySingleton3アプローチを使用することをお勧めします。

頭に浮かぶ唯一の他のことは、これはGenericsのユースケースのように見えるということです。をご覧くださいEventHandler<TEventArgs> Delegate

それとは別に、あなたが何をしようとしているのか正確に理解していないので、これ以上お勧めできません.

編集

この質問で受け入れられた回答を見てください。数年前にこれを実装した人のブログ投稿へのリンクが含まれています。車輪を再発明する必要はないようです。

于 2011-07-09T14:54:58.210 に答える