Please note that as of Release 2.3 of SimpleInjector the features discussed in this and related articles are available out of the box with the new registration method RegisterAllOpenGeneric
private static Container BootstrapSI()
{
Container container = new Container();
List<Type> types = new List<Type>();
container.RegisterManyForOpenGeneric(typeof(IObserve<>),
AccessibilityOption.PublicTypesOnly,
(service, implTypes) =>
{
//ignore implTypes as it only contains closed generic types
var assignableTypes = service.FindGenericAssignableTypes();
container.RegisterAll(service, assignableTypes);
types.AddRange(assignableTypes.Except(types));
},
AppDomain.CurrentDomain.GetAssemblies()
);
types.ForEach(type => container.Register(type));
//catch all for any services missed above
container.AutoResolveIEnumerable();
container.Verify();
return container;
}
public static ICollection<Type> FindGenericAssignableTypes(this Type service)
{
var types = service.GetPossibleGenericImplementations();
var assignables = new List<Type>();
foreach (var type in types)
{
if (service.IsAssignableFrom(type))
assignables.Add(type);
else if (type.IsGenericTypeDefinition)
try
{
Type[] args = service.GetGenericArguments();
var temp = type.MakeGenericType(args);
assignables.Add(temp);
}
catch { }
}
return assignables;
}
private static IEnumerable<Type> GetPossibleGenericImplementations(
this Type service)
{
return
from type in Assembly
.GetExecutingAssembly()
.GetExportedTypes()
from @interface in type.GetInterfaces()
where @interface.IsGenericType &&
@interface.GetGenericTypeDefinition() ==
service.GetGenericTypeDefinition()
select type;
}
public static void AutoResolveIEnumerable(this Container container)
{
container.ResolveUnregisteredType += (s, e) =>
{
if (e.UnregisteredServiceType.IsGenericType &&
e.UnregisteredServiceType.GetGenericTypeDefinition() ==
typeof(IEnumerable<>))
{
Type service = e.UnregisteredServiceType
.GetGenericArguments()
.Single();
if (service.IsGenericType)
{
var assignables = service.FindGenericAssignableTypes();
if (assignables.Any())
{
IEnumerable<object> collection =
assignables.Select(assignable =>
container.GetInstance(assignable));
var castMethod = typeof(Enumerable)
.GetMethod("Cast")
.MakeGenericMethod(service);
var castedCollection = castMethod
.Invoke(null, new object[] { collection });
e.Register(Expression.Constant(castedCollection));
}
}
}
};
}
Test Code
Container si = BootstrapSI();
var tester3 = si.GetInstance<InjectionTestClass1>();
int count3 = tester3.HandlerCount;
var tester3b = si.GetInstance<InjectionTestClass2>();
Results
– InjectionTestClass1
has 2 implementations injected – perfect
– InjectionTestClass2
fails – perfect
Happy Days SimpleInjector 2 out of 2.
(This is PoC and has not been production grade tested!)