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; }
}
}