ShaneKm ShaneKm - 1 month ago 8
C# Question

StructureMap resolve all instances for generic type at runtime

For the following container registration:

c.For(typeof(IHandler<bool>)).Use(typeof(BoolHandler));
c.For(typeof(IHandler<int>)).Use(typeof(IntHandler));


I'm trying to get a list of types at run time like so:

var test = Container.Current.Get(typeof(IHandler<>)); // doesn't work
var test = Container.Current.GetAllInstances<IHandler<object>>(); // doesn't work


I get count of 0;

Answer

You can't call Get(typeof(IHandler<>)) because it is impossible to create an instance of an open-generic type; this is impossible in the CLR.

Resolving a collection of IHandler<object> would only result any elements either when you have explicitly registered an IHandler<object> -or- when the IHandler<T> is defined as covariant, i.e. using the out keyword as IHandler<out T>. Without having in or out keywords on your interface, your interface is not variant and it is impossible to cast a closed version of an interface to another closed version of that same interface.

Only when the abstraction is defined as IHandler<out T> is is possible to assign an IHandler<string> to an IHandler<object> because T will be an output argument and string can be casted to object.

It is unlikely that this is useful to you, since handlers typically have an input argument. However, when the abstraction is defined as IHandler<in T> (which makes much more sense) this means that you can only assign an IHandler<object> from an IHandler<string>, because you can pass in a string argument into an IHandler<object> but not the other way around.

To make this more concrete, the following will compile:

interface IHandler<in T> { }

var handlers = new IHandler<string>[]
{
    new Handler<string>(),
    new Handler<object>(),
};

But the following won't:

interface IHandler<in T> { }

var handlers = new IHandler<object>[]
{
    new Handler<string>(),
    new Handler<object>(),
};

Likewise, the following will compile:

interface IHandler<out T> { }

var handlers = new IHandler<object>[]
{
    new Handler<string>(),
    new Handler<object>(),
};

But the following won't:

interface IHandler<out T> { }

var handlers = new IHandler<string>[]
{
    new Handler<string>(),
    new Handler<object>(),
};

Since this holds for C# and the CLR in general, there is no way for StructureMap (or any container) to work around this. And that's why you won't got any results.