StructureMap configure concrete classes whose interface names don't match
Given concrete classes and interfaces having names that don't match
Harvester_JohnDeere_Parsley : AbstractMachine, IParsleyHarvester
Harvester_NewHolland_Sage : AbstractMachine, ISageHarvester
Harvester_Kubota_Rosemary : AbstractMachine, IRosemaryHarvester
where the interfaces have a common parent
IParsleyHarvester : ISpiceHarvester
ISageHarvester : ISpiceHarvester
IRosemaryHarvester : ISpiceHarvester
how can StructureMap be configured so that instances of I...Harvester can be injected into the constructor e.g.
public ParsleyField(IParsleyHarvester parsleyHarvester)
without having to configure each pair individually in the Registry? e.g.
For<ISageHarvester>().Use<Harvester_NewHolland_Sage>();
I've tried scanning
Scan(x =>
{
x.AssemblyContainingType<Harvester_Kubota_Rosemary>();
x.AddAllTypesOf<ISpiceHarvester>();
but the I...Harvester interfaces don't get mapped.
Thanks!
edit:
Both answers work. @jeroenh's has the advantage that guard clauses can be added to exclude classes (for whatever reason). Here's an example based on @Mac's answer to this question.
public class HarvesterConvention : StructureMap.Graph.IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
// only interested in non abstract concrete types
if (type.IsAbstract || !type.IsClass)
return;
开发者_如何学编程 // Get interface
var interfaceType = type.GetInterface(
"I" + type.Name.Split('_').Last() + "Harvester");
if (interfaceType == null)
throw new ArgumentNullException(
"type",
type.Name+" should implement "+interfaceType);
// register (can use AddType overload method to create named types
registry.AddType(interfaceType, type);
}
}
usage:
Scan(x =>
{
x.AssemblyContainingType<Harvester_Kubota_Rosemary>();
x.Convention<HarvesterConvention>();
x.AddAllTypesOf<ISpiceHarvester>();
StructureMap does not know about your convention. You need to tell it about it by adding a custom registration convention. Implement the IRegistrationConvention interface, and add the convention to the assembly scanner:
Scan(x =>
{
x.Convention<MyConvention>();
}
I adapted a solution from @Kirschstein's answer to this question.
Scan(x =>
{
x.AssemblyContainingType<Harvester_Kubota_Rosemary>();
x.AddAllTypesOf<ISpiceHarvester>()
.NameBy(type => "I" + type.Name.Split('_').Last() + "Harvester");
Defines the way to convert the concrete class's name into its interface name for lookup purposes.
精彩评论