Wondering if it's possible to achieve the following:

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

So far I haven't been able to. Here are some code samples:

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){
        // ...
    }
}

... given these types/classes I am trying to find something that will allow me to return either ConcreteFacade1 or 2 based on how the container is configured to resolve the interface (which is where I'm having trouble).

I have tried:

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

resulting in an error stating: IWordFacade<,,,> is not a registered open generic type.

有帮助吗?

解决方案

The code you supplied is not valid C# and will not compile. You can't specify an open-generic type within the < and > tags. You have to specify a closed generic type. The following however is valid C#:

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

Although this would compile, this still will not work in Simple Injector (or any other DI framework), since frameworks always want to return you a concrete instance, but you can't create an instance for an open generic type, which is quite obvious, since an open-generic type is just a template. You need to fill in the blanks to be able to create an instance. In other words, you need a closed-generic type.

But how should the container know which closed-generic instance it should create given this open generic type? There is an endless number of possible permutations.

Although you can register an open-generic type like this:

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

You will have to request for a closed-generic interface for your DI container to be able to resolve it:

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

or

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

UPDATE

From your update I understand that there is that you either register ConcreteFacade1 or ConcreteFacade2, based on the config file, but never both. To be able to do this (in C#) you need a non-generic interface, otherwise you will only be able to program against System.Object, which is not very useful (and type-safe). So let your generic IWordFacade<T1,T2,T3,T4> inherit from the following non-generic interface:

interface IWordFacade {
    object DoSomething(object value);
}

This way you can make the following registration:

contianer.Register<IWordFacade, ConcreteFacade1>();

And you can resolve:

container.GetInstance<IWordFacade>();

Or of course inject IWordFacade into the constructor of a different type.

You now need to implement two methods into the implementations. If you have several implementations, it gets useful to define a base class. This base class can implement the non-generic interface method:

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);
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top