//некое событие
public interface IEvent{}
//обработчик события
public interface IEventHandler<T> where T : class, IEvent
{
public void HandleEvent(T @event);
}
public class EventDispatcher{
private Dictionary<Type, List<WeakReference>> _handlers = new();
private object _locker = new();
public void Subscribe<T>(IEventHandler<T> handler) where T : class, IEvent
{
var type = typeof(T);
lock(_locker){
if(!_handlers.TryGetValue(type, out var handlers)){
handlers = new();
_handlers[type] = handlers;
}
var refs = handlers.Find(x=>x.Target == handler);
if(refs is not null){
throw new InvalidOperationException();
}
refs = new(handler);
handlers.Add(refs);
}
}
public void Unsubscribe<T>(IEventHandler<T> handler) where T : class, IEvent
{
var type = typeof(T);
lock(_locker){
if(!_handlers.ContainsKey(type)){
throw new InvalidOperationException();
}
var handlers = _handlers[type];
var refs = handlers.Find(x=>x.Target == handlers);
if(refs is null){
throw new InvalidOperationException();
}
handlers.Remove(refs);
}
}
public void Handle<T>(T @event) where T : class, IEvent
{
var type = typeof(T);
//не даем подписываться пока идет обработка)))
lock(_locker){
if(!_handlers.ContainsKey(type)){
return;
}
var handlers = _handlers[type];
List<WeakReference> toRemove = new();
foreach(var handlerRef in handlers){
if(!handlerRef.IsAlive){
toRemove.Add(handlerRef);
continue;
}
if(handlerRef.Target is null){
toRemove.Add(handlerRef);
continue;
}
var handler = handlerRef.Target as IEventHandler<T>;
if(handler is null){
toRemove.Add(handlerRef);
continue;
}
handler.HandleEvent(@event);
}
foreach(var i in toRemove){
handlers.Remove(i);
}
}
}
}