【发布时间】:2020-06-15 13:24:03
【问题描述】:
我正在尝试优化我的代码以注入一个类列表,这些类实现一个接口
IEventHandler<TEvent>.
我有以下结构:
public interface IEventHandlerMarker { }
public interface IEventHandler<in TEvent> : IEventHandlerMarker where TEvent : IEvent
{
Task Handle(TEvent eventItem);
}
public interface IEvent
{
public DateTime Timestamp { get; set; }
}
我在 DI 中注册了标记接口 IEventHandlerMarker,并且在访问处理程序时,我目前执行以下操作:
public EventPublisherService(IEnumerable<IEventHandlerMarker> eventHandlers)
{
// Check and and all event handlers
foreach (IEventHandlerMarker item in eventHandlers)
{
AddEventHandler(item);
}
}
在我的AddEventHandler 方法中,我将它们过滤到IEventHandler<>,如下所示:
Type handlerType = eventHandlerMarker.GetType().GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEventHandler<>));
到目前为止一切正常,但我想摆脱标记界面和过滤器逻辑。所以我将处理程序的注册更改为以下方法,这似乎按预期工作:
public static IServiceCollection AddEventHandlers(this IServiceCollection serviceDescriptors, params Assembly[] handlerAssemblies)
{
Type genericHandlerType = typeof(IEventHandler<>);
foreach (var implementationType in genericHandlerType.GetTypesWithGenericInterfacesInAssemblies(handlerAssemblies))
{
Type interfaceType = implementationType.GetGenericInterfaceType(genericHandlerType);
serviceDescriptors.AddSingleton(interfaceType, implementationType);
}
return serviceDescriptors;
}
public static List<Type> GetTypesWithGenericInterfacesInAssemblies(this Type source, params Assembly[] assemblies)
{
return assemblies
.SelectMany(currentAssembly => currentAssembly.GetTypes()
.Where(type => type.GetInterfaces().Any(
interfaceItem => interfaceItem.IsGenericType
&& interfaceItem.GetGenericTypeDefinition().Equals(source))))
.ToList();
}
我把EventPublisherService的构造函数改成如下:
public EventPublisherService(IServiceProvider serviceProvider)
{
Type ienumerableOfIEventHandlerType = typeof(IEnumerable<>).MakeGenericType(typeof(IEventHandler<>));
object result = serviceProvider.GetService(ienumerableOfIEventHandlerType);
}
但结果总是为空。 我在 Stackoverflow 上搜索并查看了一些文章,发现了以下文章: https://stackoverflow.com/a/51504151/1099519
我不确定这是不是同样的情况,因为我没有使用工厂。
使用的版本:.NET Core 3.1 和 Autofac 4.9.4 用于依赖注入管理。
【问题讨论】:
-
除非我遗漏了什么,否则 Autofac 会自行完成您需要的一切。检查这个问题:stackoverflow.com/questions/16757945/…
-
我没有问题,注册课程时,这似乎工作正常 - 我的问题是,我无法从 ServiceProvider 访问它们。
-
在chapter 15 的DIPP&P 中有一个关于在MS.DI 中注册泛型类型的广泛讨论。例如,看一下this 部分。然而,该章的结论是,MS.DI 受到严重限制,使得这类场景非常难以实现。
-
我同意@Steven,MS DI 肯定达不到 Autofac 的水平。然而,它比 Autofac 更轻巧,可以满足许多不需要 Autofac 等重量级的需求
-
@DominikAmon 我不清楚您要达到的目标。您是否需要解析所有 IEventHandler,而不管 TEvent 是什么,还是只需要为您发布的 TEvent 解析?它们有两种不同的解决方案。另外,您说注册类没有问题,但是对于 Autofac 在一行代码中所做的事情似乎非常冗长。最后,您是否考虑过将匹配的 TEvents 与 IEventHandlers 缓存在字典中?对每个事件派发进行反射将非常低效。
标签: c# generics .net-core dependency-injection autofac