繁体   English   中英

Autofac如何在运行时注册和解析通用接口?

[英]Autofac how to register and resolve generic interface at runtime?

我无法在运行时解决通用接口实现。 我正在使用一个事件总线,它将根据事件的类型解析事件处理程序。 当我尝试在没有通用实现的情况下解决事件处理程序时,一切都按预期工作。 我想实现一个通用接口,这样我就可以有一个基本的 class 来处理特定类型的事件。

在创建通用实现之前,我遇到了以下情况:

public interface IEvent
    {
        Guid EntityId { get; set; }
    }

public interface IEventHandler<TEvent> where TEvent : IEvent
    {
        Task Handle(TEvent @event);
    }

public class EventBus
    {
        private readonly IComponentContext _context;

        public EventBus(IComponentContext context)
        {
            _context = context;
        }

        public async Task HandleEvent<TEvent>(TEvent @event) where TEvent : IEvent
        {
            var handler = _context.Resolve<IEventHandler<TEvent>>();
            await handler.Handle(@event);
        }
    }

我注册 eventHandlers 如下:

builder.RegisterAssemblyTypes(ThisAssembly).AsClosedTypesOf(typeof(IEventHandler<>));

示例实现:

public class FooEventHandler :
        IEventHandler<FooArchivedEvent>,
        IEventHandler<FooRestoredEvent>,
        IEventHandler<FooSomethingElseHappenedEvent>
    {
        private readonly IRepository<Foo> _repository;

        public FooEventHandler(IRepository<Foo> repository)
        {
            _repository = repository;
        }

        public async Task Handle(FooArchivedEvent @event)
        {
            var Foo = await _repository.Get(@event.EntityId);
            Foo.Archive();
        }

        public async Task Handle(FooRestoredEvent @event)
        {
            var Foo = await _repository.Get(@event.EntityId);
            Foo.Restore();
        }

        public async Task Handle(FooSomethingElseHappenedEvent @event)
        {
            // do something else with Foo
        }
    }

    public class BarEventHandler :
        IEventHandler<BarArchivedEvent>,
        IEventHandler<BarRestoredEvent>
    {
        private readonly IRepository<Bar> _repository;

        public BarEventHandler(IRepository<Bar> repository)
        {
            _repository = repository;
        }

        public async Task Handle(BarArchivedEvent @event)
        {
            var Bar = await _repository.Get(@event.EntityId);
            Bar.Archive();
        }

        public async Task Handle(BarRestoredEvent @event)
        {
            var Bar = await _repository.Get(@event.EntityId);
            Bar.Restore();
        }
    }

当我将 FooArchivedEvent 传递给事件总线时,事件总线将解析所需的事件处理程序。 如您所见,我有一些重复的代码要在基本事件处理程序中解决。 这是我在创建通用实现(不会编译)之前尝试过的:

public class BaseEventHandler<TEntity, TArchivedEvent, TRestoredEvent> :
        IEventHandler<TArchivedEvent>,
        IEventHandler<TRestoredEvent>
        where TEntity : class
        where TArchivedEvent : IEvent
        where TRestoredEvent : IEvent
    {
        public Task Handle(TArchivedEvent @event)
        {
            throw new NotImplementedException();
        }

        public Task Handle(TRestoredEvent @event)
        {
            throw new NotImplementedException();
        }
    }

所以我创建了一个可以编译的通用基础 class,但是我不知道如何在事件总线中解析通用事件处理程序。 通用基础 class:

public abstract class BaseEventHandler<TEntity> :
        IEventHandler<IArchivedEvent<TEntity>>,
        IEventHandler<IRestoredEvent<TEntity>>
        where TEntity : Archivable
    {
        protected readonly IRepository<TEntity> _repository;

        public BaseEventHandler(IRepository<TEntity> repository)
        {
            _repository = repository;
        }

        public virtual async Task Handle(IArchivedEvent<TEntity> @event)
        {
            var entity = await _repository.Get(@event.EntityId);
            entity.Archive();
        }

        public async virtual Task Handle(IRestoredEvent<TEntity> @event)
        {
            var entity = await _repository.Get(@event.EntityId);
            entity.Archive();
        }
    }

我的新 FooEventHandler 现在看起来像这样:

public class FooEventHandler : BaseEventHandler<Foo>,
        IEventHandler<FooSomethingElseHappenedEvent>
    {
        public FooEventHandler(IRepository<Foo> repository) : base(repository)
        {
        }

        public Task Handle(FooSomethingElseHappenedEvent @event)
        {
            // do something else with Foo
        }
    }

现在,当我将 FooArchivedEvent 传递给事件总线时,事件总线无法解析事件处理程序。 在注册部分我需要做些什么,还是无法解决这样的通用实现?

我最终编写了一个方法来检查注册处理程序的类型的每个接口:

private IEventHandler<TEvent> GetHandler<TEvent>(Type type = null) where TEvent : IEvent
        {
            object handler;
            type = type ?? typeof(TEvent);
            if (_container.TryResolve(typeof(IEventHandler<>).MakeGenericType(type), out handler))
            {
                return (IEventHandler<TEvent>)handler;
            }
            else
            {
                foreach (var t in type.GetInterfaces())
                {
                    var h = GetHandler<TEvent>(t);
                    if (h != null)
                        return h;
                }
            }
            return null;
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM