Common instance of grand child objects using ctor injection

Jul 22, 2009 at 2:09 AM

I'm trying to move from using StructureMap to Unity so I can use aspects of the EntLib.

When using Unity to construct objects that have multi level dependencies, Unity constructs a new instance of each child object for each dependency. This differs from StructureMap where the same instance resolved for each type is cached for subsequent requests.

Can Unity be configured to provide equivalent behaviour?

For example please see the sample code:

using System;
using System.Diagnostics;

using Microsoft.Practices.Unity;

namespace UnityTest
{
    public interface IGrandChild
    {
        int InstanceId { get; }
    }

    public class GrandChild : IGrandChild
    {
        private static int _nextInstanceId = 1;

        public GrandChild()
        {
            InstanceId = _nextInstanceId++;
        }

        public int InstanceId { get; private set; }
    }

    public interface IChild1
    {
        int InstanceId { get; }
    }

    public class Child1 : IChild1
    {
        public Child1(IGrandChild sessReq)
        {
            SessReq = sessReq;
        }

        public IGrandChild SessReq { get; private set; }

        public int InstanceId { get { return SessReq.InstanceId; } }
    }

    public interface IChild2
    {
        int InstanceId { get; }
    }

    public class Child2 : IChild2
    {
        public Child2(IGrandChild sessReq)
        {
            SessReq = sessReq;
        }

        public IGrandChild SessReq { get; private set; }

        public int InstanceId { get { return SessReq.InstanceId; } }
    }

    public class Parent
    {
        public Parent(IChild1 child1, IChild2 child2)
        {
            Child1 = child1;
            Child2 = child2;
        }

        public IChild1 Child1 { get; private set; }
        public IChild2 Child2 { get; private set; }

        public string Sessions()
        {
            return Child1.InstanceId + ": " + Child2.InstanceId;
        }
    }

    public static class Program
    {
        static void Main()
        {
            var cont = new UnityContainer()
                .RegisterType<IGrandChild, GrandChild>()
                .RegisterType<IChild1, Child1>()
                .RegisterType<IChild2, Child2>()
                .RegisterType<Parent>();

            var testParent = cont.Resolve<Parent>();
            Debug.WriteLine(testParent.Sessions());

            testParent = cont.Resolve<Parent>();
            Debug.WriteLine(testParent.Sessions());
        }
    }
} 

 With Unity the output is :

1: 2
3: 4
ie 2 instances of the GrandChild class are instantiated. One for each Child dependency for Parent.

Where as with StructureMap the output is :

1: 1
2: 2
ie 1 instance of the GrandChild class is instantiated for Child1 and used again for Child2 to resolve Parent. 

Structure map is not creating a new GrandChild class for the resolution of Child2, it's passing the instance used for the Child1. I've been using that to share a common nHibernate session across multiple repository classes within a single ASP MVC controller.

Thanks,

Simon Bateman

 

Jul 22, 2009 at 7:02 AM

Per-buildup singletons are something I've been trying to get into Unity for a couple versions, but it never quite percolated to the top of the stack. It's definately on the plate for Unity 2.0. In the meantime, you could do it via an extension, but it's a little tricky, since it requires changing the dynamic codegen process so that the singleton gets stored away for future use after it's constructed.

 

Jul 23, 2009 at 2:01 AM

Thanks - Having multiple copies of the IoC managed data isn't so bad. I just need to create one instance of a class per build up and share it across multiple instances.

Any ideas?

Jul 24, 2009 at 6:02 AM

It's a grotesque hack, but you could create a child container, register the types as singletons in the child, and then throw away the container. Although that'd also dispose the singleton; you'd need to use a custom lifetime manager that didn't call dispose.

Like I said, it's a little tricky. :-)

Jul 24, 2009 at 7:58 AM

Thanks again - for what its worth adding the option to control build-up lifetimes along the lines of a context being passed to a lifetime manger would be an extremely useful feature. With canned managers like ContainerControlledLifetimeManager etc users get coarse control with the ability to write specific managers for custom cases.

It gets my vote for V2.0 functionality.