public interface IPublisher { void Publish<T>(T data); void Subscribe<T>(object subscriber, Action<T> pHandler); void Unsubscribe(object subscriber); void Unsubscribe<T>(object subscriber, Action<T> pHandler); }
public class Publisher : IPublisher { public Publisher() { } internal List<Handler> _handlers = new List<Handler>(); internal object _locker = new object(); public void Publish<T>(T data = default(T)) { List<Handler> handlerList; lock (_locker) { handlerList = new List<Handler>(_handlers.Count); var handlersToRemove = new List<Handler>(_handlers.Count); foreach (var handler in _handlers) { if (!handler.Sender.IsAlive) { handlersToRemove.Add(handler); } else if (handler.Type.GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())) { handlerList.Add(handler); } } foreach (var htr in handlersToRemove) { _handlers.Remove(htr); } } foreach (var hl in handlerList) { ((Action<T>)hl.Action)(data); } } public void Subscribe<T>(Action<T> pHandler) { Subscribe(this, pHandler); } public void Subscribe<T>(object subscriber, Action<T> pHandler) { var item = new Handler { Action = pHandler, Sender = new WeakReference(subscriber), Type = typeof(T) }; lock (_locker) { _handlers.Add(item); } } public void Unsubscribe() { Unsubscribe(this); } public void Unsubscribe(object subscriber) { lock (_locker) { var query = _handlers.Where(a => !a.Sender.IsAlive || a.Sender.Target.Equals(subscriber)); foreach (var h in query.ToList()) { _handlers.Remove(h); } } } public void Unsubscribe<T>() { Unsubscribe<T>(this); } public void Unsubscribe<T>(Action<T> pHandler) { Unsubscribe(this, pHandler); } public void Unsubscribe<T>(object subscriber, Action<T> pHandler = null) { lock (_locker) { var query = _handlers.Where(a => !a.Sender.IsAlive || a.Sender.Target.Equals(subscriber) && a.Type == typeof(T)); if (pHandler != null) { query = query.Where(a => a.Action.Equals(pHandler)); } foreach (var h in query.ToList()) { _handlers.Remove(h); } } } internal class Handler { public Delegate Action { get; set; } public WeakReference Sender { get; set; } public Type Type { get; set; } } }