How to handle cycling object graph creation

Sep 26, 2012 at 1:45 PM

I have a cyclic reference between my concreate class. Some articles say that I can try to use Property injection instead of constructor injection to handle cycle. I can't refactor my code to remove cycle.

I tried property injection but still Container.Resolve throws stackoverflow due to cycle.

UnityContainer container = new UnityContainer();

container.RegisterType<ICycleA, CycleA>(new InjectionProperty("Dependency"));

container.RegisterType<ICycleB, CycleB>(new InjectionProperty("Dependency"));

 var a = container.Resolve<ICycleA>(); //throws stackoverflow

 class CycleB : ICycleB
    {
       public CycleB()
        { }


        public string Name
        {
            get { return "I am B"; }
            
        }

        public ICycleA Dependency
        {
            get;
            set;
        }
    }


class CycleA : ICycleA
    {
        public CycleA()
        {
        }

        public ICycleB Dependency
        {
            get;
            set;
        }

        public string Name
        {
            get { return " ia am A"; }
        }
    }
Sep 26, 2012 at 1:59 PM
Edited Sep 26, 2012 at 2:32 PM

Give at least one of the two classes a lifetime of type PerResolveLifetimeManager. That breaks the cycle. This solution also works for constructor injection.

var container = new UnityContainer();
container.RegisterType<ICycleA, CycleA>(new PerResolveLifetimeManager(), 
  new InjectionProperty("Dependency"));
container.RegisterType<ICycleB, CycleB>(new InjectionProperty("Dependency"));
var a = container.Resolve<ICycleA>();

Question: If you can't change the code, how did you switch from constructor injection to property injection?

Sep 26, 2012 at 2:27 PM

I tried both property and constructor injection with PerrResolveLifetimeManager but still failing. can't change code meant, I can't refactor so that cyclic dependency is removed.

container.RegisterType<ICycleA, CycleA>(new PerResolveLifetimeManager());
container.RegisterType<ICycleB, CycleB>();

 

Sep 26, 2012 at 2:32 PM

Sorry, my bad. I does't work for ctor injection. There was an error in my test setup.

Sep 26, 2012 at 3:40 PM

even property injection is not working even after using PerResolveLifetimeManager.

Is there a way this can be handled in unity?

Thanks

Sep 26, 2012 at 4:06 PM

My test runs green.

[TestClass]
public class BreakTheCycleFixture
{
  [TestMethod]
  public void PerResolve_Lifetime_Should_Cure_StackOverflowException_OnCyclicDependency_InProperties()
  {
    var container = new UnityContainer();
    container.RegisterType<ICycleA, CycleA>(new PerResolveLifetimeManager(), new InjectionProperty("Dependency"));
    container.RegisterType<ICycleB, CycleB>(new InjectionProperty("Dependency"));
    var a = container.Resolve<ICycleA>();
    Assert.IsInstanceOfType(a, typeof(CycleA));
    Assert.IsInstanceOfType(a.Dependency, typeof(CycleB));
    Assert.AreSame(a, a.Dependency.Dependency);
  }
}
class CycleB : ICycleB
{
  public ICycleA Dependency { get; set; }
}
class CycleA : ICycleA
{
  public ICycleB Dependency { get; set; }
}
interface ICycleB
{
  ICycleA Dependency { get; set; }
}
interface ICycleA
{
  ICycleB Dependency { get; set; }
}