本地事件总线

2021年7月13日 1810点热度 0人点赞 0条评论
内容纲要

空接口,发布者订阅者通讯,需要一个实现了 IEventData 的类。

    /// <summary>
    /// 事件数据
    /// </summary>
    public interface IEventData
    {
    }

事件,订阅者需要实现这个类型,当发布者发布一个 IEventData 类型的数据时,此事件会被触发。

当然,你也可以创建一个同步事件。

    /// <summary>
    /// 异步事件
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IAsyncEventHandler<in T> where T : IEventData
    {
        Task HandleEventAsync(T eventData);
    }

事件总线接口,订阅者可以通过此此接口订阅 IEventData,发布者也可以通过此发布 IEventData。

    public interface IEventBus
    {
        /// <summary>
        /// 发布事件
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventData"></param>
        /// <returns></returns>
        Task PublishAsync<TEventData>(TEventData eventData) where TEventData : IEventData;

        /// <summary>
        /// 订阅事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        void Register<TEvent>() where TEvent : IAsyncEventHandler<IEventData>;

        /// <summary>
        /// 取消订阅事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        void Unregister<TEvent>() where TEvent : IAsyncEventHandler<IEventData>;
    }

实现事件总线:

    public class EventBus : IEventBus
    {
        private readonly IServiceProvider _services;
        private readonly ILogger _logger;

        public EventBus(IServiceProvider services, ILogger logger)
        {
            _services = services;
            _logger = logger;
        }

        static EventBus()
        {
            _handlerFactories = new ConcurrentDictionary<Type, List<Type>>();
        }
        private readonly static ConcurrentDictionary<Type, List<Type>> _handlerFactories;

        public async Task PublishAsync<TEventData>(TEventData eventData) where TEventData : IEventData
        {
            try
            {
                if (!_handlerFactories.TryGetValue(eventData.GetType(), out var list))
                {
                    return;
                }
                _logger.LogInformation($"Eventbus : {typeof(TEventData)} , Registers : {string.Join(",", list.Select(x => x.Name))}");
                List<Task> tasks = new List<Task>();
                foreach (var item in list)
                {
                    var obj = _services.GetRequiredService(item);
                    var eventObj = (IAsyncEventHandler<IEventData>)obj;
                    tasks.Add(eventObj.HandleEventAsync(eventData));
                }
                await Task.WhenAll();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Eventbus : {typeof(TEventData).Name}", eventData);
            }
        }

        public void Register<TEvent>() where TEvent : IAsyncEventHandler<IEventData>
        {

            try
            {
                // 获取事件参数
                if (!typeof(TEvent).IsGenericType) return;
                var iEventDataType = ((System.Reflection.TypeInfo)typeof(TEvent)).GenericTypeParameters.FirstOrDefault();

                if (_handlerFactories.TryGetValue(iEventDataType, out var list)) { }
                else
                {
                    list = new List<Type>();
                    _ = _handlerFactories.TryAdd(iEventDataType, list);
                }
                list.Add(typeof(TEvent));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Eventbus : {typeof(TEvent).Name}");
            }
        }

        public void Unregister<TEvent>() where TEvent : IAsyncEventHandler<IEventData>
        {
            try
            {
                // 获取事件参数
                if (!typeof(TEvent).IsGenericType) return;
                var iEventDataType = ((System.Reflection.TypeInfo)typeof(TEvent)).GenericTypeParameters.FirstOrDefault();

                if (_handlerFactories.TryGetValue(iEventDataType, out var list))
                {
                }
                else
                {
                    list = new List<Type>();
                    _ = _handlerFactories.TryAdd(iEventDataType, list);
                }
                list.Remove(typeof(TEvent));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Eventbus : {typeof(TEvent).Name}");
            }
        }
    }

由于每一个事件都实现 IAsyncEventHandler ,其中事件也可以使用依赖注入,因此需要将所有实现了 IAsyncEventHandler 的事件都放到依赖注入中,这些才有意义。

痴者工良

高级程序员劝退师

文章评论