Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

Wicked Cool Jobs

Syndication

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
“SmartInstance” in StructureMap 2.5

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.


Posted Wed, Aug 20 2008 2:43 PM by Jeremy D. Miller

[Advertisement]

Comments

Scott wrote re: “SmartInstance” in StructureMap 2.5
on Wed, Aug 20 2008 10:13 PM

I agree on setter injection usually, but I will say that the WithCtorArg is much more indicative of the intent, so at the very least, thank you for the name change :) (or add i guess)

WithProperty was confusing because when you first see it you assume that it means "do setter injection here".  Well, I assumed that anyway.

Jeremy D. Miller wrote re: “SmartInstance” in StructureMap 2.5
on Wed, Aug 20 2008 11:39 PM

Live and learn Scott.  This has been a good learning experience for me in terms of learning how to create better API's.  

On the other hand, I had a colleague one time that used to say "oh no, here comes another learning opportunity"

Steve Bohlen wrote re: “SmartInstance” in StructureMap 2.5
on Thu, Aug 21 2008 6:44 AM

I just have to chime in here to ask a question (not a flame, a real question): Is there any such thing as TOO verbose a fluent interface?

I'm (generally) a fan of mostly-fluent interfaces for a number of things, but IMHO this is starting to get gratuitious to the point of actually DIMINISHING readability rather than improving it.  As the 'quest-for-sentence-like-structures' starts to introduce pronouns, prepositions, and other similar spoken/written language constructs, the signal to noise ratio in many FI implementations starts to just hurt my brain :)

Clearly your opinion is that the above level of 'fluency' is desirable, but I wonder in your own opinion if you would consider (as a design philosophy) that there is such a thing as too fluent an interface?

Is the goal REALLY to be able to say When.I.have.a.type.called.this.please.create.a.concrete.instance.of.this.type.unless.the.constructor.contains.an.argument.with.a.value.of.2.in.which.case.return.this.other.type().

Its not clear to me that this is either attainable OR desirable unless the plan is for a business analysts to read (and maintain) it after I am dead and buried.

Thoughts?

Jeremy D. Miller wrote re: “SmartInstance” in StructureMap 2.5
on Thu, Aug 21 2008 8:32 AM

@Steve,

I don't particularly disagree with anything you said.  If the "fluency" is doing more harm than good in terms of readability and effort, then yeah, it's a bad thing.

Truth be told, the "TheDefault.Is.Blah" syntax has somewhat to do with me being able to reuse a certain piece of code in the expression builders than purely a regard for readability.

Dew Drop - August 21, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - August 21, 2008 | Alvin Ashcraft's Morning Dew
on Thu, Aug 21 2008 10:10 AM

Pingback from  Dew Drop - August 21, 2008 | Alvin Ashcraft's Morning Dew

Scott wrote re: “SmartInstance” in StructureMap 2.5
on Fri, Aug 22 2008 10:12 AM

@Steve I agree wholeheartedly with the premise of your comment.  It can get very easy to abuse the FI and reduce the solubility of the code.

However, I find the one here in SM largely understandable and easy to work with. The constraints of the language/platform have always led us down paths we don't necessarily like all the time. It's the nature of the beast.

@Jeremy Don't take my initial comment as anything other than face value. I have a hard enough time getting API design right for consumption by an internal small team. I don't at all envy your job (with structuremap) of creating an API that works for a wide variety of consumers.  Keep up the great work brotha.

RhysC wrote re: “SmartInstance” in StructureMap 2.5
on Thu, Aug 28 2008 11:42 AM

"Java guys are exactly the opposite."

It funny you say that becuase i have java buddies that seem to disagree in terms of using annotations/attributes over extrenal mapping or configs too, specifically in hibernate, but i assume this goes for other potentiall invasive framework libraries. Weird.

Anyway Jeremy i am with you, i certainly prefer ctor injection over setter, but hey as long as everyone is happy. Good Job.

Recent Faves Tagged With "intellisense" : MyNetFaves wrote Recent Faves Tagged With "intellisense" : MyNetFaves
on Wed, Oct 15 2008 11:50 PM

Pingback from  Recent Faves Tagged With "intellisense" : MyNetFaves

Jeremy D. Miller -- The Shade Tree Developer wrote A Gentle Quickstart for StructureMap 2.5
on Sun, Nov 30 2008 10:56 PM

The most general question I get with StructureMap is “how do I get started?” Personally, I’d recommend

Community Blogs wrote A Gentle Quickstart for StructureMap 2.5
on Sun, Nov 30 2008 11:48 PM

The most general question I get with StructureMap is “how do I get started?” Personally, I’d recommend

A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas wrote A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas
on Tue, Dec 2 2008 10:16 AM

Pingback from  A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas

A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas wrote A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas
on Wed, Dec 3 2008 11:04 AM

Pingback from  A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas

A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas wrote A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas
on Thu, Dec 4 2008 11:09 AM

Pingback from  A Gentle Quickstart for StructureMap 2.5 - taccato! trend tracker, cool hunting, new business ideas

Dave's Box wrote "I can't believe Microsoft didn't make [Enter API Name Here] public"
on Tue, Dec 9 2008 11:58 AM

Jeremy Miller takes a dig at the BCL team with his post, I love Ayende (and OSS) : From one of Ayende

Ayende @ Rahien wrote Consenting Adults
on Tue, Dec 9 2008 5:32 PM

Consenting Adults

Jeff Handley wrote Consenting adults and public displays of affection
on Wed, Dec 10 2008 1:54 AM

Consenting adults and public displays of affection

Kurt Harriger wrote re: “SmartInstance” in StructureMap 2.5
on Wed, Jul 1 2009 12:16 PM

One major advantage of setter injection over constructor injection that I have found is when the type is meant to be subclassed.  With constructor injection the derived type also needs same constructor args plus whatever it needs.  This isn't necessarily so bad if the base class has only one or two required dependencies, but if you later add another dependency to the base class then you need to update the constructors of all derived types.   With setter injection you do not need to change the derived types.

I also try to provide a default implementation where possible, and prefer setter injection to override default rather than constructor making it much easier to setup container when default implementation does what you want.

peter wrote re: “SmartInstance” in StructureMap 2.5
on Sun, Feb 21 2010 9:11 PM

Hi!

a question :

say I want to get back an instance of ISomething but to give it a value for the constructor. eg.

public class something : ISomething{

public something  (IOtherthing  other_stuff){..}

....}

now in code I got something like this..

public void do_something_with(IOtherthing thisThing) {

var something = ObjectFactory.Get<ISomething>(? thisThing????)

Is that possible? how do I configure it & use it

}

Jeremy D. Miller wrote re: “SmartInstance” in StructureMap 2.5
on Sun, Feb 21 2010 10:45 PM

@Peter,

ObjectFactory.With(my other thing).GetInstance<ISomething>()

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Devlicio.us