使用 Autofac 解析构造函数中泛型的 IEnumerable
本文关键字:泛型 IEnumerable 构造函数 Autofac 使用 | 更新日期: 2024-10-29 18:59:50
所以我有一个抽象的工厂类,这个想法是在这个工厂的构造函数中,我将从 autofac 传递我感兴趣的所有注册服务的IEnumerable
。 此工厂中有一个传递参数的方法,代码将遍历IEnumerable
并返回匹配的服务。 像馅饼一样简单,抽象的工厂模式。
最近在工厂返回的接口中引入了一个泛型类型,我不确定如何编写构造函数,以便 autofac 知道仍然返回所有注册的服务,并且基本上忽略泛型。
一些代码:
我的界面:
public interface IRunnerServices<in T>
{
void Create(T entity);
}
接口的一些实现
public class RunnerServiceA : IRunnerServices<A>
{
public void Create(A entity);
}
public class RunnerServiceB : IRunnerServices<B>
{
public void Create(B entity);
}
public class RunnerServiceC : IRunnerServices<C>
{
public void Create(C entity);
}
// Many, many more...
在我的作曲根中,我像这样注册这些服务
builder.RegisterType<RunnerServicesA>().As<IRunnerServices<A>>();
builder.RegisterType<RunnerServicesB>().As<IRunnerServices<B>>();
builder.RegisterType<RunnerServicesC>().As<IRunnerServices<C>>();
正如您所知,A,B,C都继承自同一个基类
public class A : LetterBase
{ }
public class B : LetterBase
{ }
public class C : LetterBase
{ }
现在,我的抽象工厂
public class RunnerServicesFactory
{
private readonly IEnumerable<IRunnerServices<????>> _candidates;
public RunnerServicesFactory(IEnumerable<IRunnerServices<????>> candidates)
{
_candidates = candidates;
}
public IRunnerServices<????> Create(int discriminator)
{
return _candidates.First(c => c.Discriminator == discriminator);
}
}
问题在于我在上面的构造函数和其他声明中提供了什么,????让 autofac 知道它应该在此泛型的所有注册服务中传递?
我已经试过了,但没有运气,因为 autofac 什么也没通过
IEnumerable<IRunnerServices<LetterBase>>
将RunnerServiceA
实现转换为IRunnerService<LetterBase>
,您需要使用 out 泛型关键字修饰符进行协变IRunnerService<T>
这是不可能的,因为您有一个接受T
参数的方法。
.net 不允许你RunnerServiceA
强制转换为IRunnerService<LetterBase>
你可以尝试通过执行以下简单的代码:
var runnerService = (IRunnerServices<LetterBase>)new RunnerServiceA();
// Throws an InvalidCastException
一种可能的解决方案是使IRunnerService<T>
协变如下所示:
public interface IRunnerServices<out T>
where T : LetterBase
{
void Create(LetterBase entity);
}
通过这样做,您将能够将RunnerServiceA
转换为IRunnerService<LetterBase>
并执行以下代码:
IEnumerable<IRunnerServices<LetterBase>> runners = new IRunnerServices<LetterBase>[] {
new RunnerServiceA(),
new RunnerServiceB()
};
然后,Autofac 将能够解析IEnumerable<IRunnerServices<LetterBase>>
如果RunnerService
被注册为 IRunnerServices<LetterBase>
顺便说一下,你在做什么让我考虑一下IIndex<TKey, T>
:
public class RunnerServicesFactory
{
private readonly IIndex<Char, IRunnerServices<LetterBase>> _candidates;
public RunnerServicesFactory(IIndex<Char, IRunnerServices<LetterBase>> candidates)
{
_candidates = candidates;
}
public IRunnerServices<LetterBase> Create(Char discriminator)
{
return _candidates[discriminator];
}
}
注册将是这样的:
builder.RegisterType<RunnerServiceA>().Keyed<IRunnerServices<LetterBase>>('A');
builder.RegisterType<RunnerServiceB>().Keyed<IRunnerServices<LetterBase>>('B');
builder.RegisterType<RunnerServiceC>().Keyed<IRunnerServices<LetterBase>>('C');