【发布时间】:2020-06-11 09:47:50
【问题描述】:
假设您有几个开放的通用抽象类:
public abstract class AbstractActionHandler<TInput>
{
public abstract Task Action(TInput input);
}
public abstract class AbstractFunctionHandler<TInput, TOutput>
{
public abstract Task<TOutput> Function(TInput input);
}
那么你有几个实现:
public class IntActionClass : AbstractActionHandler<int>
{
public Task Action(int input)
{
//do some work...
}
}
public class StringActionClass : AbstractActionHandler<string>
{
public Task Action(string input)
{
//do some work...
}
}
public class IntFunctionClass : AbstractFunctionHandler<int, string>
{
public Task<string> Function(int input)
{
//do some work...
}
}
public class StringFunctionClass : AbstractFunctionHandler<string, bool>
{
public Task<bool> Function(string input)
{
//do some work...
}
}
现在您想在 IoC 容器中注册程序集中的所有实现,以便解决依赖关系:
var builder = new ContainerBuilder();
var openGenericTypes = new[]
{
typeof(AbstractActionHandler<>),
typeof(AbstractFunctionHandler<,>)
};
var assembly = Assembly.GetExecutingAssembly();
var implementationTypes = new List<Type>();
foreach (var openGenericType in openGenericTypes)
{
var types = assembly.GetTypes()
.Where(type => type.IsAssignableFrom(openGenericType))
.Where(type => !type.IsAbstract);
builder.RegisterTypes(types.ToArray())
.AsClosedTypesOf(openGenericType)
.InstancePerDependency();
implementationTypes.AddRange(types);
}
var container = builder.Build();
现在您有一个 implementationTypes 列表,并且您想要遍历该列表并将每个类型的实例解析为它们的封闭泛型类型。这就是问题发生的地方:
foreach (var type in implementationTypes)
{
var handler = container.Resolve(type);
// handler is of type object but needs to be of its closed generic type
// ie. AbstractAbstractHandler<int>
if (type == typeof(AbstractActionHandler<>))
{
// This should be called for all classes closing AbstractActionHandler<>
ConstructActionHandler<TInput>(handler); // calls AbstractActionHandler.Action
}
else if (type == typeof(AbstractFunctionHandler<,>))
{
// This should be called for all classes closing AbstractFunctionHandler<>
ConstructFunctionHandler<TInput, TOutput>(handler); // calls AbstractFunctionHandler.Function
}
}
public void ConstructActionHandler<TInput>(AbstractActionHandler<TInput> handler)
{
var actionHandlerWrapperDelegate = new Func<TInput, Task>(async (input) =>
{
await actionHandler.Action(input);
});
// ....
}
所以第一个问题是:如何从类型实例中解析出封闭泛型类型的实例?
我想过创建一个通用的包装类,它可以用 Activator.CreateInstance() 实例化,并让包装器解析正确的处理程序,但我不确定这是否是正确的方法。
此外,假设您想要一个不同通用参数类型的处理程序列表:
// this would not be possible
var actionHandlers = new List<AbstractActionHandler<TInput>>();
// this would however be possible
var actionHandlers = new List<IActionHandler>();
var functionHandlers = new List<IFunctionHandler>();
你想通过它们的类型参数以某种方式连接它们:
foreach (var actionHandler in actionHandlers)
{
var actionHandlerTypeArgument = handler.GetType().GenericTypeArguments.First();
var functionHandler = functionHandlers.Find(handler =>
handler.GetType().GenericTypeArguments.First() == actionHandlerTypeArgument);
var wrapper = new Func<TInput>(async input =>
{
var output = functionHandler.Function(input);
actionHandler.Action(output);
});
// ...
}
如何将 IActionHandler 或 IFunctionHandler 的实例向下转换为其封闭的通用接口?
这个问题的答案可能与第一个问题的答案相同。我只是将它们分开,因为解决第一个问题的方法可能是错误的方法。
任何类型的输入都将受到高度赞赏! 如果有更好的方法,我也很高兴听到。
谢谢!
【问题讨论】:
标签: c# generics reflection dependency-injection autofac