2016-04-21 88 views
0

所以我有一个抽象工厂类的,这种想法是,在这家工厂的构造,我会从autofac所有已注册的服务我很感兴趣的IEnumerable通过在这个工厂有一个传递参数的方法,代码将遍历IEnumerable并返回匹配的服务。容易如馅饼,抽象的工厂模式。解决通用的IEnumerable的构造函数中使用Autofac

的问题是,我最近在我的接口工厂返回引入了泛型类型,我不知道怎么写的构造函数,因此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>你需要IRunnerService<T>协与出通用关键字改性剂,它不因为您有一种方法可以接受T参数。

。净不允许你投RunnerServiceAIRunnerService<LetterBase>您可以通过这个简单的代码尝试:

var runnerService = (IRunnerServices<LetterBase>)new RunnerServiceA(); 
// Throws an InvalidCastException 

一个可能的解决办法是让IRunnerService<T>协这样的:

public interface IRunnerServices<out T> 
    where T : LetterBase 
{ 
    void Create(LetterBase entity); 
} 

通过这样做,你将能够投RunnerServiceAIRunnerService<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'); 
+0

我并不完全了解你的covarient解决方案,你是否输错了什么。你声明IRunnerServices ,但是没有任何输出类型为T. – raterus

+0

@raterus'out'修饰符仅用于允许.net将'RunnerServiceA'强制转换为'IRunnerService '。 –

相关问题