I really like StructureMap as an IOC-framework especially the convention based registration. Now I try to do the following: I want to add all types that implement a specific interface when the class has a default (no parameters) constructor. And the types must be created using this constructor.
This is what I have untill now, which registers the correct types, but how do I specify that the default constructor should be used when creating an instance.
public class MyRegistry : Registry
{
public MyRegistry()
{
Scan(
x =>
开发者_运维技巧 {
x.AssemblyContainingType<IUseCase>();
x.Exclude(t => !HasDefaultConstructor(t));
x.AddAllTypesOf<IUseCase>();
});
}
private static bool HasDefaultConstructor(Type type)
{
var _constructors = type.GetConstructors();
return _constructors.Any(c => IsDefaultConstructor(c));
}
private static bool IsDefaultConstructor(ConstructorInfo constructor)
{
return !constructor.GetParameters().Any();
}
}
There are a few ways to force StructureMap to use a specific constructor. The simplest is to put the DefaultConstructor attribute on the constructor you want to use. Assuming you don't want to do that, you would have to create a custom RegistrationConvention.
public class UseCaseRegistrationConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (type.IsAbstract || type.IsInterface || type.IsEnum)
return;
var useCaseInterface = type.GetInterface("IUseCase");
if (useCaseInterface == null)
return;
var constructor = type.GetConstructors().FirstOrDefault(c => !c.GetParameters().Any());
if (constructor != null)
{
registry.For(useCaseInterface).Add(c => constructor.Invoke(new object[0]));
}
}
}
Then use it in your Scan call:
Scan(x =>
{
x.AssemblyContainingType<IUseCase>();
x.With(new UseCaseRegistrationConvention());
});
精彩评论