![](/img/trans.png)
[英]Resolve IEnumerable of All Types that Implement Generic Interface in Autofac
[英]Resolve IEnumerable of a generic in constructor with Autofac
所以我有一个抽象的工厂类,我的想法是在这个工厂的构造函数中,我将从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>
RunnerServiceA
为IRunnerService<LetterBase>
您需要使用out generic关键字修饰符使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()
};
然后,如果RunnerService
注册为IRunnerServices<LetterBase>
Autofac将能够解析IEnumerable<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');
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.