c# - Autofac如何在运行时注册和解析通用接口?
问题描述
我无法在运行时解决通用接口实现。我正在使用一个事件总线,它将根据事件的类型解析事件处理程序。当我尝试在没有通用实现的情况下解决事件处理程序时,一切都按预期工作。我想实现一个通用接口,这样我就可以拥有一个处理特定类型事件的基类。
在创建通用实现之前,我遇到了以下情况:
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();
}
}
所以我创建了一个可以编译的通用基类,但是我不知道如何在事件总线中解析通用事件处理程序。通用基类:
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;
}
推荐阅读
- angular - Angular 的 Kendo UI:如何在网格中定义最小宽度
- snappy - 如何在 LZ4 和 Snappy 压缩之间做出选择?
- python - 如何在 Python 中创建共现矩阵?
- c++ - 在 C++ Microsoft vsCode 中使用外部库
- javascript - div重新加载后的Ajax / Jquery显示(非引导)弹出窗口/模型
- flutter - 亚洲的反向地理编码
- javascript - GRID 雷达图自定义 Amcharts
- python - 如何让 OpenPose 更准确
- java - 如何提高 HttpClient 响应的处理速度?
- perl - perl - Net::SSLeay 和服务器名称指示