events.Dispatch( , );
public void Dispatch<TEvent, TSender, TArg>(TEvent e, TSender sender, TArg arg)
TEvent
, TSender
and TArg
independent. But we know that an event must unambiguously determine its parameters. We describe it as follows:
public void Dispatch<TEvent, TSender, TArg>(IEvent<TEvent, TSender, TArg> e, TSender sender, TArg arg) where TEvent : IEvent<TEvent, TSender, TArg>
IEvent
? Let us consider in more detail the limitations of type parameters (the where
construct). It can be seen that the type of TEvent
recursively defined through itself. Therefore, IEvent
define IEvent
as well:
public abstract class IEvent<TEvent, TSender, TArg> where TEvent : IEvent<TEvent, TSender, TArg> { }
public class StartTurnEvent : IEvent<StartTurnEvent, Player, int> { }
events.Dispatch(new StartTurnEvent(), player, 123);
Dispatch
method:
public void Dispatch<TEvent, TSender, TArg>(IEvent<TEvent, TSender, TArg> e, TSender sender, TArg arg) where TEvent : IEvent<TEvent, TSender, TArg> { foreach (var action in handlers.Get<Action<TSender, TArg>>(typeof(TEvent))) { action(sender, arg); } }
Dispatch
without instantiating:
events.Dispatch((StartTurnEvent)null, player, 123);
null
. We put it into a constant:
public abstract class IEvent<TEvent, TSender, TArg> where TEvent : IEvent<TEvent, TSender, TArg> { public readonly static TEvent Tag = null; }
// 0: Unity3D /* */ // 1: enum' enum Events { StartTurn } // 2: public class StartTurnMessage : IMessage<Player, int> { public StartTurnMessage(Player player, int value) : base(player, value) { } } // 3: public class StartTurnEvent : IEvent<StartTurnEvent, Player, int> { }
// 0: Unity3D player.SendMessage("OnStartTurn", 123); // IDE // 1: enum' events.Dispatch(Events.StartTurn, player, 123); // // 2: events.Dispatch(new StartTurnMessage(player, 123)); // 3: events.Dispatch(StartTurnEvent.Tag, player, 123);
using System; using System.Collections.Generic; using System.Linq; using Collection = System.Collections.Generic.HashSet<object>; namespace SteamSquad.Gameplay { public class EventBus { private readonly Container handlers = new Container(); public void Unsubscribe<TEvent, TSender>(IEvent<TEvent, TSender> tag, Action<TSender> action) where TEvent : IEvent<TEvent, TSender> { handlers.Remove(typeof(TEvent), action); } public void Unsubscribe<TEvent, TSender, TArg>(IEvent<TEvent, TSender, TArg> tag, Action<TSender, TArg> action) where TEvent : IEvent<TEvent, TSender, TArg> { handlers.Remove(typeof(TEvent), action); } public void Subscribe<TEvent, TSender>(IEvent<TEvent, TSender> tag, Action<TSender> action) where TEvent : IEvent<TEvent, TSender> { handlers.Add(typeof(TEvent), action); } public void Subscribe<TEvent, TSender, TArg>(IEvent<TEvent, TSender, TArg> tag, Action<TSender, TArg> action) where TEvent : IEvent<TEvent, TSender, TArg> { handlers.Add(typeof(TEvent), action); } public void Dispatch<TEvent, TSender>(IEvent<TEvent, TSender> tag, TSender sender) where TEvent : IEvent<TEvent, TSender> { foreach (var action in handlers.Get<Action<TSender>>(typeof(TEvent))) { action(sender); } } public void Dispatch<TEvent, TSender, TArg>(IEvent<TEvent, TSender, TArg> tag, TSender sender, TArg arg) where TEvent : IEvent<TEvent, TSender, TArg> { foreach (var action in handlers.Get<Action<TSender, TArg>>(typeof(TEvent))) { action(sender, arg); } } public abstract class IEvent<TEvent, TSender> where TEvent : IEvent<TEvent, TSender> { public readonly static TEvent Tag = null; } public abstract class IEvent<TEvent, TSender, TArg> where TEvent : IEvent<TEvent, TSender, TArg> { public readonly static TEvent Tag = null; } private class Container { private readonly Dictionary<Type, Collection> container = new Dictionary<Type, Collection>(); public void Add(Type type, object action) { Collection collection; if (!container.TryGetValue(type, out collection)) { container.Add(type, collection = new Collection()); } collection.Add(action); } public void Remove(Type type, object action) { container[type].Remove(action); } public IEnumerable<TAction> Get<TAction>(Type type) { Collection collection; if (container.TryGetValue(type, out collection)) { return collection.OfType<TAction>(); } return Enumerable.Empty<TAction>(); } } } }
Source: https://habr.com/ru/post/245487/