From the feedback on the StructureMap Google group, Chad and I have hashed out a new Fluent Interface expressions for explicitly defining constructor arguments and setter values (I still think Setter Injection is a design smell, but I've been vociferously voted down). The problems in the current version is that SetProperty() is overloaded to mean either setter or constructor arguments. The underlying mechanisms in StructureMap stores the information the same way, but the API was causing real confusion. So, to alleviate that confusion and also to utilize some of the new .Net 3.5 goodness, I present the new language:
Defining primitive constructor arguments -- WithCtorArg("name").EqualTo("value") or WithCtorArg("name").EqualToAppSetting("key")
[Test]
public void DeepInstanceTest_with_SmartInstance()
{
assertThingMatches(registry =>
{
registry.ForRequestedType<Thing>().TheDefault.Is.OfConcreteType<Thing>()
.WithCtorArg("name").EqualTo("Jeremy")
.WithCtorArg("count").EqualTo(4)
.WithCtorArg("average").EqualTo(.333)
.SetterDependency<Rule>().Is(x =>
{
x.OfConcreteType<WidgetRule>().SetterDependency<IWidget>().Is(
c => c.OfConcreteType<ColorWidget>().WithCtorArg("color").EqualTo("yellow"));
});
});
}
Defining primitive setter properties - just uses a Lambda expression that will be applied to the object as soon as it's built. Intellisense and compiler safety are good things, so you might as well use it. StructureMap now supports optional setter injection, meaning that you no longer need to do the [Setter] attributes in the concrete classes. If you specify the value of a setter, StructureMap will use that value regardless of whether or not the [Setter] property exists. The same rule applies to non-primitive setter dependencies.
instance.SetProperty(x => x.Name = "Jeremy")
Overriding Constructor Dependencies - Only when you want to override the auto wiring behavior. I've chosen to use a Nested Closure for defining the child instance of the IWidget constructor argument below. You could also replace x.Object() with x.OfConcreteType<T> or x.ConstructedBy(Func<T>) or other options inside the Is() method. I chose this solution because I thought it would make it easier to guide the user to the possible options.
instance.CtorDependency<IWidget>("widget").Is(x => x.Object(widget))
Overriding Setter Dependencies - Setter dependencies (non-primitive types) are specified much like constructor arguments. Your options are to say: .SetterDependency<T>().Is(whatever) or .SetterDependency<T>(x => x.Setter).Is(whatever).
registry.ForRequestedType<Thing>().TheDefault.Is.OfConcreteType<Thing>()
.WithCtorArg("name").EqualTo("Jeremy")
.WithCtorArg("count").EqualTo(4)
.WithCtorArg("average").EqualTo(.333)
.SetterDependency<Rule>().Is(x =>
{
x.OfConcreteType<WidgetRule>().SetterDependency<IWidget>().Is(
c => c.OfConcreteType<ColorWidget>().WithCtorArg("color").EqualTo("yellow"));
});
Explicitly defining an array of dependencies - I get into this scenario with configuring business rules. Let's say you have a class that depends on an array of some other type of service. That syntax looks like:
registry.ForRequestedType<Processor>().TheDefault.Is.OfConcreteType<Processor>()
.WithCtorArg("name").EqualTo("Jeremy")
.TheArrayOf<IHandler>().Contains(x =>
{
x.References("Two");
x.References("One");
});
or
IContainer container = new Container(r =>
{
r.ForRequestedType<Processor>().TheDefault.Is.OfConcreteType<Processor>()
.WithCtorArg("name").EqualTo("Jeremy")
.TheArrayOf<IHandler>().Contains(x =>
{
x.OfConcreteType<Handler1>();
x.OfConcreteType<Handler2>();
x.OfConcreteType<Handler3>();
});
});
In this case, I was lazy and made no distinction between constructor arguments and setter arguments.
Adding additional instances of a given type - Sometimes you're adding more than one instance of a given service type to StructureMap. You may be fetching by ObjectFactory.GetNamedInstance<T>(name) or by ObjectFactory.GetAllInstances<T>(). Either way, this syntax will work.
registry.ForRequestedType<IService>().AddInstances(x =>
{
x.OfConcreteType<ColorService>().WithName("Red")
.WithCtorArg("color").EqualTo("Red");
x.Object(new ColorService("Yellow")).WithName("Yellow");
x.ConstructedBy(() => new ColorService("Purple")).WithName("Purple");
x.OfConcreteType<ColorService>().WithName("Decorated").WithCtorArg("color").EqualTo(
"Orange");
}));
Thoughts? Comments? I should say here that StructureMap 2.5 will be about 95% backwards compatible with the existing FI, so no worries about converting.
It's funny, but I generally think that with few exceptions the Constructor Injection is the preferable approach, but I continuously read that the Java guys are exactly the opposite. To each his or her own I guess.
Source Click Here.
No comments:
Post a Comment
Post your comments here: