使用Simple Injector解决通用接口

时间:2014-03-17 01:56:38

标签: c# generics dependency-injection simple-injector

想知道是否有可能实现以下目标:

container.GetInstance<IWordFacade<,,,>>();

到目前为止,我还没能做到。以下是一些代码示例:

IWordFacade<T1,T2,T3,T4>{
    T1 DoSomething(T2);
}

public class ConcreteFacade1 : IWordFacade<int,long,double,decimal>{
    int DoSomething(long param){
        //....
    }
}

public class ConcreteFacade2 : IWordFacade<short,string,float,char>{
    short DoSomething(string param){
        // ...
    }
}

...给定这些类型/类我试图找到一些东西,允许我根据容器配置如何解析接口(这是我遇到麻烦的地方)返回ConcreteFacade1或2。

我试过了:

container.Register(typeof(IWordFacade<,,,>), typeof(ConcreteFacade1));

导致错误说明:IWordFacade&lt; ,,,&gt;不是注册的开放泛型类型。

1 个答案:

答案 0 :(得分:3)

您提供的代码无效C#,无法编译。您不能在&lt;中指定open-generic类型。和&gt;标签。您必须指定一个封闭的泛型类型。但是以下是有效的C#:

container.GetInstance(typeof(IWordFacade<,,,>));

虽然这会编译,但这仍然无法在Simple Injector(或任何其他DI框架)中工作,因为框架总是希望返回一个具体的实例,但是你不能为开放的泛型类型创建一个实例,很明显,因为开放泛型类型只是一个模板。您需要填写空白才能创建实例。换句话说,您需要一个封闭的泛型类型。

但是,对于这个开放的泛型类型,容器应该如何知道它应该创建哪个封闭通用实例?存在无数可能的排列。

虽然您可以注册这样的开放泛型类型:

container.Register(typeof(IWordFacade<,,,>), typeof(WordImpl<,,,>));

您必须要求DI容器的封闭通用接口才能解决它:

container.GetInstance<IWordFacade<Foo, Bar, FooBar>>();

container.GetInstance(typeof(IWordFacade<Foo, Bar, FooBar>));

<强>更新

根据您的更新,我了解您可以根据配置文件注册ConcreteFacade1ConcreteFacade2,但不要同时注册。为了能够执行此操作(在C#中),您需要一个非泛型接口,否则您将只能对System.Object进行编程,这不是非常有用(并且类型安全)。因此,让您的通用IWordFacade<T1,T2,T3,T4>继承自以下非通用接口:

interface IWordFacade {
    object DoSomething(object value);
}

这样您可以进行以下注册:

contianer.Register<IWordFacade, ConcreteFacade1>();

你可以解决:

container.GetInstance<IWordFacade>();

或者当然将IWordFacade注入到不同类型的构造函数中。

您现在需要在实现中实现两种方法。如果您有多个实现,那么定义基类会很有用。该基类可以实现非泛型接口方法:

public abstract class WordFacadeBase<T1, T2, T3, T4> : IWordFacade<T1, T2, T3, T4> {
    public abstract T1 DoSomething(T2 value);
    object IWordFacade.DoSomething(object value) {
        return DoSomething(T2)value);
    }
}