I have a generic interface which has many implementations, possibly in different assemblies. I have Simple Injector 4.3.0 installed in my project via NuGet, and want to register the implementors as a collection. My configuration is verified by Simple Injector without incident, but the container returns an empty collection when GetAllInstances is called.
A MCVE analogous to my code:
using SimpleInjector;
using System;
using System.Linq;
namespace SIMultiInterfaceTest
{
public interface IFoo<T> { }
public class Bar<T> : IFoo<T> { }
public class Baz<T> : IFoo<T> { }
class Program
{
static void Main(string[] args)
{
var container = new Container();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
container.Collection.Register(typeof(IFoo<>), assemblies);
container.Verify();
Console.WriteLine($"{container.GetAllInstances<IFoo<int>>().Count()} in collection");
Console.ReadLine();
}
}
}
For reference, I am trying to implement the registration scenario mentioned towards the end of this section of the SI docs (ctrl+f: "As an example, imagine the scenario where you have a CustomerValidator type and a GoldCustomerValidator type").
My gut instinct is that this might have something to do with Bar<T>
and Baz<T>
being open generic types - the example shows only closed types being registered in this way. I'm not convinced, however, as this seems contrary to the design choices which would lead to this entirely valid line, also from the same page in the docs:
container.Register(typeof(IValidate<>), typeof(NullValidator<>));
This behavior is explained in the XML comments for the Collection.Register(Type, Assembly[])
overload you are calling:
Registers all concrete, non-generic types (both public and internal) that are defined in the given set of
assemblies
and that implement the givenserviceType
with a default lifestyle and register them as a collection ofserviceType
. [emphasis mine]
Your types, however, are generic. Generic types are not registered because they often require special care.
To register these generic types, there are two options.
You can use Collection.Append
to prepend or append these types to the collection:
// Bar<T> is prepended
container.Collection.Append(typeof(IFoo<>), typeof(Bar<>));
// All non-generic registrations next
container.Collection.Register(typeof(IFoo<>), assemblies);
// Baz is appended. It will be the last element of the collection
container.Collection.Append(typeof(IFoo<>), typeof(Baz<>));
The second option is to use GetTypesToRegister
to get all types, including generic types:
var types = container.GetTypesToRegister(
typeof(IFoo<>),
assemblies,
new TypesToRegisterOptions { IncludeGenericTypeDefinitions = true });
container.Collection.Register(typeof(IFoo<>), types);
Here we call GetTypesToRegister
while supplying a TypesToRegisterOptions
that indicates it should return generic types as well. This list of types is supplied to the Collection.Register(Type, Type[])
overload.
Do note, however, that in this second option the order in which types are registered is undetermined, and could possibly change every time you recompile or even restart the application. If this behavior is unsuited, you will have to order the set of types before supplying it to Collection.Register
.