![](/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.