Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

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
Conditional Object Construction in StructureMap (i.e. Fun with Lambdas)

What if you want StructureMap to return a different Type for users in one role versus user without that role?  What if you'd like to return one Type if the database is reachable and another Type if the database is determined to be offline?  I kept getting questions like that on the StructureMap group, so I applied some Lambda-fu in the latest release to create the new "Conditional Instance." This blog is excerpted from the StructureMap documentation here.

 

There have been several questions on the StructureMap users list about doing conditional construction (i.e., return this object if this condition, else this other object).  In order to meet this apparent need, StructureMap 2.5.2 introduces the new ConditionalInstance that allows a user to effectively switch the active Instance based on a Predicate<IContext> boolean test.  Here's a quick example of using the new Conditional() syntax of InstanceExpression:

            var container = new Container(x =>

            {

                x.InstanceOf<Rule>().Is.Conditional(o =>

                {

                    o.If(c => false).ThenIt.Is.OfConcreteType<ARule>();

                    o.If(c => true).ThenIt.IsThis(GREEN);

                    o.TheDefault.IsThis(RED);

                }).WithName("conditional");

            });

The syntax above is configuring and attaching a ConditionalInstance object.  Internally, this syntax is telling the ConditionalInstance to:

  1. Return the concrete type "ARule" if the condition "c => false" is met (in real usage the predicate would do something more intelligent ;-) )
  2. Else, return a Rule object specified by the variable named GREEN if the condition "c => true" is met
  3. Finally, if none of the predicates match, return the Rule object specified by the variable named RED

The syntax "If( predicate ).*************" uses an InstanceExpression and all possible Instance types are available.

Internally, the ConditionalInstance looks like this:

    public class ConditionalInstance<T> : ExpressedInstance<ConditionalInstance<T>>

    {

        // Conditional Instance keeps track of zero or more internal Instance

        // objects against a Predicate<IContext> condition

        private readonly List<InstanceCase> _cases = new List<InstanceCase>();

 

        // The "default" Instance to use if none of the conditional predicates

        // are met.  If this is not explicitly defined, the ConditionalInstance

        // will simply look for the default Instance of the desired

        // PluginType

        public Instance _default = new DefaultInstance();

    }

 

    public class InstanceCase

    {

        public Predicate<IContext> Predicate { get; set; }

        public Instance Instance { get; set; }

    }

When a call is made to container.GetInstance<Rule>("conditional"):

  1. Internally, the Container object finds the ConditionalInstance object that was configured and named "conditional" for the PluginType "Rule"
  2. The Container invokes the ConditionalInstance.Build(Type, BuildSession) method
  3. The ConditionalInstance evaluates its InstanceCase collection to find the first InstanceCase that matches the current IContext and invokes the internal Instance of that InstanceCase
  4. Lastly, if ConditionalInstance does not find any matching InstanceCase objects, it will invoke its default Instance to build the requested object

It might be easier to just see the code for this:

        protected override object build(Type pluginType, BuildSession session)

        {

            // Find the first InstanceCase that matches the BuildSession/IContext

            var instanceCase = _cases.Find(c => c.Predicate(session));

 

            // Use the Instance from the InstanceCase if it exists,

            // otherwise, use the "default"

            var instance = instanceCase == null ? _default : instanceCase.Instance;

 

            // delegate to the chosen Instance

            return instance.Build(pluginType, session);

        }

Please see Using the Session Context for more information on what is possible with the IContext.


Posted Sun, Jan 18 2009 11:19 PM by Jeremy D. Miller
Filed under:

[Advertisement]

Comments

Chris wrote re: Conditional Object Construction in StructureMap (i.e. Fun with Lambdas)
on Mon, Jan 19 2009 3:39 AM

hi

wow - that looks ace. Ive been trying to find out if something like this was possible with an IoC container

I asked on Stackoverflow but didnt get any satisfactory answers

stackoverflow.com/.../does-an-ioc-container-replace-the-use-of-factories

would you have any comment on the suitability of what you describe here to addressing the situation in the linked question

it would be much appreciated - I find myself writing code like that alot and to have it automated would be great

Dew Drop - January 19, 2009 | Alvin Ashcraft's Morning Dew wrote Dew Drop - January 19, 2009 | Alvin Ashcraft's Morning Dew
on Mon, Jan 19 2009 10:16 AM

Pingback from  Dew Drop - January 19, 2009 | Alvin Ashcraft's Morning Dew

IoC - StructureMap Links « QuantuMatrix’s Weblog wrote IoC - StructureMap Links &laquo; QuantuMatrix&#8217;s Weblog
on Mon, Jan 19 2009 12:16 PM

Pingback from  IoC - StructureMap Links &laquo; QuantuMatrix&#8217;s Weblog

Daniel Fernandes wrote re: Conditional Object Construction in StructureMap (i.e. Fun with Lambdas)
on Tue, Jan 20 2009 8:58 AM

@Jeremy:

Your choice of wording makes it as if you've implemented this feature against your will ?

I personally think what you've done is great because it should be possible to put brokers functionality at any stage of a graph retrieval.

The problem I had with the normal use case of IoC is that to differentiate two instances that do essentially the same thing by implementing the same contract but are implemented in different ways.

It's usually either by convention (parameter name) or using the typing to provide unique distinction which is all well and good but it always felt to me an over-simplification of object construction.

So in my view what you've done is giving an easy API to provide a hook at the core of the IoC container and can truly enable more dynamic scenarios without ending up with a type soup.

So for this I say thank you!

Daniel

jdn wrote re: Conditional Object Construction in StructureMap (i.e. Fun with Lambdas)
on Tue, Jan 20 2009 1:32 PM

That's sweet.

Jeremy D. Miller wrote re: Conditional Object Construction in StructureMap (i.e. Fun with Lambdas)
on Tue, Jan 20 2009 1:35 PM

@Daniel,

I did this feature mostly because it sounded like a cool thing to see if I could do it.  Whether it's widely used or not, shrug.  We'll see.

DotNetShoutout wrote Conditional Object Construction in StructureMap (i.e. Fun with Lambdas) - Jeremy D. Miller
on Mon, Feb 23 2009 5:13 AM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Add a Comment

(required)  
(optional)
(required)  
Remember Me?