一个简单的事件总线(Event Bus)用于.NET技术

24
我希望创建一个非常简单的事件总线,它允许任何客户端订阅特定类型的事件,并且当任何发布者使用 EventBus.PushEvent() 方法将事件推送到总线上时,只有订阅了该特定事件类型的客户端才会收到该事件。
我正在使用 C# 和 .NET 2.0。

基于Redis的消息队列 https://github.com/antirez/disque - ZOXEXIVO
8个回答

26

Tiny Messenger是一个不错的选择,我已经在一个实时项目中使用了2.5年。以下是一些来自Wiki的代码示例(链接如下):

发布

messageHub.Publish(new MyMessage());

订阅

messageHub.Subscribe<MyMessage>((m) => { MessageBox.Show("Message Received!"); });
messageHub.Subscribe<MyMessageAgain>((m) => { MessageBox.Show("Message Received!"); }, (m) => m.Content == "Testing");

这份代码在 GitHub 上: https://github.com/grumpydev/TinyMessenger

维基页面在这里: https://github.com/grumpydev/TinyMessenger/wiki

此外还有一个 Nuget 包。

Install-Package TinyMessenger

4
对于 TinyMessenger,一个微小但强大的消息总线,我给予+1 的支持。 - Mhmmd

9

这是受安卓EventBus启发的一个库,但更为简单:

public class EventBus
{
    public static EventBus Instance { get { return instance ?? (instance = new EventBus()); } }

    public void Register(object listener)
    {
        if (!listeners.Any(l => l.Listener == listener))
            listeners.Add(new EventListenerWrapper(listener));
    }

    public void Unregister(object listener)
    {
        listeners.RemoveAll(l => l.Listener == listener);
    }

    public void PostEvent(object e)
    {
        listeners.Where(l => l.EventType == e.GetType()).ToList().ForEach(l => l.PostEvent(e));
    }

    private static EventBus instance;

    private EventBus() { }

    private List<EventListenerWrapper> listeners = new List<EventListenerWrapper>();

    private class EventListenerWrapper
    {
        public object Listener { get; private set; }
        public Type EventType { get; private set; }

        private MethodBase method;

        public EventListenerWrapper(object listener)
        {
            Listener = listener;

            Type type = listener.GetType();

            method = type.GetMethod("OnEvent");
            if (method == null)
                throw new ArgumentException("Class " + type.Name + " does not containt method OnEvent");

            ParameterInfo[] parameters = method.GetParameters();
            if (parameters.Length != 1)
                throw new ArgumentException("Method OnEvent of class " + type.Name + " have invalid number of parameters (should be one)");

            EventType = parameters[0].ParameterType;
        }

        public void PostEvent(object e)
        {
            method.Invoke(Listener, new[] { e });
        }
    }      
}

应用场景:

public class OnProgressChangedEvent
{

    public int Progress { get; private set; }

    public OnProgressChangedEvent(int progress)
    {
        Progress = progress;
    }
}

public class SomeForm : Form
{
    // ...

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        EventBus.Instance.Register(this);
    }

    public void OnEvent(OnProgressChangedEvent e)
    {
        progressBar.Value = e.Progress;
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        EventBus.Instance.Unregister(this);
    }
}

public class SomeWorkerSomewhere
{
    void OnDoWork()
    {
        // ...

        EventBus.Instance.PostEvent(new OnProgressChangedEvent(progress));

        // ...
    }
}

2

2

2
你也可以查看Unity扩展: http://msdn.microsoft.com/en-us/library/cc440958.aspx
[Publishes("TimerTick")]
public event EventHandler Expired;
private void OnTick(Object sender, EventArgs e)
{
  timer.Stop();
  OnExpired(this);
}

[SubscribesTo("TimerTick")]
public void OnTimerExpired(Object sender, EventArgs e)
{
  EventHandler handlers = ChangeLight;
  if(handlers != null)
  {
    handlers(this, EventArgs.Empty);
  }
  currentLight = ( currentLight + 1 ) % 3;
  timer.Duration = lightTimes[currentLight];
  timer.Start();
}

有更好的吗?

1

0

0

你应该看一下Hibernating Rhinos的第三集,Ayende的屏幕录制系列 - "实现事件代理"。

它展示了如何使用Windsor实现一个非常简单的事件代理来连接事物。源代码也包括在内。

所提出的事件代理解决方案非常简单,但是增加解决方案以允许在事件中传递参数不需要太多时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接