[英]C# Check if type implements a specific generic interface with unknown types
我有多个依赖注入处理程序,并希望找到合适的处理程序来解决任务。 我终于找到了相应的处理程序(在 class HandlerResolver
),但我无法将Handler
程序作为方法结果返回。
接口:
public interface IMessage
{
}
public interface IHandler<TRoot, in TMessage> where TRoot : class
{
public abstract TRoot Apply(TRoot root, TMessage message);
}
// Marker interface to register/resolve dependency injected handlers
public interface IHandler
{
}
处理程序:
public class Handler1: IHandler<MyRoot, Message1>, IHandler
{
public MyRoot Apply(MyRoot aggregateRoot, Message1 message)
{
...
return aggregateRoot;
}
}
public class Handler2: IHandler<MyRoot, Message2>, IHandler
{
public MyRoot Apply(MyRoot aggregateRoot, Message2 message)
{
...
return aggregateRoot;
}
}
留言:
public class Message1 : ICaseMessage
{
...
}
public class Message2 : ICaseMessage
{
...
}
DI注册:
services.AddScoped<IResolver, HandlerResolver>();
services.AddScoped<IHandler, Handler1>();
services.AddScoped<IHandler, Handler2>();
解决处理程序:
public class HandlerResolver : IResolver
{
private IEnumerable<IHandler> Handlers { get; } // DI injected handlers
public HandlerResolver(IEnumerable<IHandler> handlers)
{
Handlers = handlers;
}
public IHandler<TRoot, TMessage> GetHandler<TRoot, TMessage>(TRoot root, TMessage message)
where TRoot : class
where TMessage : class,
{
var concreteRootType = root.GetType();
var concreteMessageType = message.GetType();
var handlerOrNull = this.Handlers.FirstOrDefault(p =>
{
var genericArguments = p.GetType().GetInterfaces().First().GenericTypeArguments;
return genericArguments[0] == concreteAggregateType &&
genericArguments[1] == concreteMessageType;
});
if (handlerOrNull == null)
{
throw new NotImplementedException($"No Handler Found");
}
else
{
return handlerOrNull as IHandler<TRoot, TMessage>;
}
}
}
返回 handlerOrNull 作为 IHandler<TRoot, TMessage>;
这将始终返回null
。 我认为这是由于解析。 似乎试图将其解析为IHandler<TRoot, IMessage>
由于某种原因不起作用。
我也试过这个解决方案如何确定一个类型是否实现了一个特定的泛型接口类型,如果泛型类型未知,该接口类型就不起作用。
通常,您应该注册对象的实际完整类型,即
services.AddScoped<IHandler<MyRoot, Message1>, Handler1>();
这应该可以让您为您的类型获得正确的服务:
services.GetRequiredService<IHandler<MyRoot, Message1>>()
至少我认为这是用于 Microsoft.Extensions.DependencyInjection 的正确方法,它不是我熟悉的库。
请注意,您需要注册并解析实际类型。 解析IHandler<MyRoot, IMessage>
将不起作用,因为这意味着处理程序可以采用任何类型的IMessage
参数,但它们不能,它们只能采用Message1
/ Message2
。
逆变的工作方向与您似乎认为的相反,即您将拥有一个Handler1: IHandler<MyRoot, IMessage>
可以转换为IHandler<MyRoot, Message1>
。 这是有效的,因为处理程序承诺接受所有IMessage
实现,而Message1
就是这样一个实现。 但它可能会给解析带来麻烦,因为解析通常需要精确的类型匹配。
您可以通过手动解决来解决这个问题,即从通用类型 arguments 中为您的接口获取类型 object,然后手动遍历这些类型,检查它们是否可分配。 但是,如果您不想做任何奇怪的事情,我不建议这样做。
var handlerType = typeof(IHandler<TRoot, TMessage>);
Handlers.FirstOrDefault(p => handlerType.IsAssignableFrom(p.GetType()));
实际的处理程序类型应该是IHandler<MyRoot, Message1>
或IHandler<MyRoot, Message2>
取决于泛型类型参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.