所以我有一个抽象的工厂类,我的想法是在这个工厂的构造函数中,我将从 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>>
答案 0 :(得分:0)
为了将RunnerServiceA
实施转换为IRunnerService<LetterBase>
,您需要使用{generic}关键字修饰符进行IRunnerService<T>
协变,这是不可能的,因为您有一种方法可以接受T
1}}参数。
.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()
};
如果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');