问题
I've done quite a bit of googling and searching here on SO, but couldn't find a similar question or answer.
In typical SM configuration you can add multiple named instances for a single PluginType:
ForRequestedType<IFoo>()
.AddInstances( x => {
x.OfConcreteType<FooA>().WithName( "FooA" );
x.OfConcreteType<FooB>().WithName( "FooB" );
} );
No problem there. The problem is that I can't do the same when creating a profile. Most examples explaining how to use profiles use the For<>()
method of the passed ProfileExpression
:
CreateProfile( "Default", p => {
p.For<IFoo>().UseConcreteType<FooC>();
} );
I can't seem to find a way to add multiple named instances for the same PluginType as you can do above with regular configuration. The only other method available through ProfileExpression
is Type<>()
, but I'm not sure if it can be used for this purpose.
Edit: I tried to use Type<>()
instead of For<>()
and it seems to be taking me in the right direction, but I bumped into another problem. To better explain it here's a better example of what I'm trying to do (this is what I posted to the structuremap-users group, no answer yet):
ObjectFactory.Initialize( x => {
x.CreateProfile( "Nissan", p =>
{
p.Type<ICar>().Is.OfConcreteType<NewNissanCar>().WithName( "New" );
p.Type<ICar>().Is.OfConcreteType<OldNissanCar>().WithName( "Old" );
} );
x.CreateProfile( "Honda", p =>
{
p.Type<ICar>().Is.OfConcreteType<NewHondaCar>().WithName( "New" );
p.Type<ICar>().Is.OfConcreteType<OldHondaCar>().WithName( "Old" );
} );
} );
ObjectFactory.Profile = "Nissan";
ICar newCar = ObjectFactory.GetNamedInstance<ICar>( "New" ); // -> returns NewHondaCar
ICar car = ObjectFactory.GetInstance<ICar>(); // -> returns OldNissanCar
So even though I set the profile to "Nissan", GetNamedInstance<>("New")
returned an instance from the incorrect profile - it should've returned NewNissanCar
instead of NewHondaCar
.
Interestingly, GetInstance<>()
uses the correct profile, but because I can't pass an instance name, it returns an arbitrary concrete type from that profile that implements ICar
(I guess it just returns the last concrete type added for that interface).
回答1:
I'm not 100% sure on the syntax, but I believe this is correct:
container = new Container(x => {
x.ForRequestedType<IFoo>()
.AddInstances(y =>
{
y.OfConcreteType<FooA>().WithName("FooA");
y.OfConcreteType<FooB>().WithName("FooB");
});
x.CreateProfile("Default")
.For<IFoo>().UseNamedInstance("FooA");
});
回答2:
It doesn't look like StructureMap respects named instances at the profile level. I just tried the car example with SM 2.6.3 and got the same results. You can also see it in the output of ObjectFactory.WhatDoIHave()
:
ICar (ConsoleApplication1.ICar)
Scoped as: Transient
"New" Configured Instance of ConsoleApplication1.NewHondaCar, ConsoleApplication1
"Old" Configured Instance of ConsoleApplication1.OldHondaCar, ConsoleApplication1
It looks like the profiles might be implemented internally by using the name as well, which would explain why it's not supported. When I registered a non-named instance for each profile, I see this in the output:
ICar (ConsoleApplication1.ICar)
Scoped as: Transient
"Default Instance for Profile Nissan" Configured Instance of ConsoleApplication1.NewNissanCar, ConsoleApplication1
"Default Instance for Profile Honda" Configured Instance of ConsoleApplication1.NewHondaCar, ConsoleApplication1
Notice how the name of the profile is actually part of the instance key's name. I haven't walked through the code, but this is what appears to be happening.
来源:https://stackoverflow.com/questions/1288192/how-to-setup-named-instances-using-structuremap-profiles