Question

Consider situation when you need to create some recursively nested things, for example like that:

    public interface IRecurrentTestNodeFactory
    {
        RecurrentTestNode Create(int num);
    }

    public class RecurrentTestNode
    {
        public int Num { get; set; }
        public RecurrentTestNode Child { get; set; }

        public RecurrentTestNode(int num, IRecurrentTestNodeFactory factory)
        {
            Num = num;
            Child = num > 0 ? factory.Create(num - 1) : null;
        }
    }

Obvious implementation is like that:

    public class ManualRecurrentTestNodeFactory : IRecurrentTestNodeFactory
    {
        public RecurrentTestNode Create(int num)
        {
            return new RecurrentTestNode(num, this);
        }
    }

    [Test]
    public void ManualRecurrentTest()
    {
        var root = new ManualRecurrentTestNodeFactory().Create(1);
        Assert.NotNull(root);
        Assert.AreEqual(1, root.Num);
        Assert.NotNull(root.Child);
        Assert.AreEqual(0, root.Child.Num);
        Assert.Null(root.Child.Child);
    }

This test passes. But if you'll try to do the same thing with Windsor's Typed Factory Facility like that:

    [Test]
    public void RecurrentTest()
    {
        var windsor = new WindsorContainer();
        windsor.Kernel.AddFacility<TypedFactoryFacility>();
        windsor.Register(Component.For<IRecurrentTestNodeFactory>().AsFactory());
        windsor.Register(Component.For<RecurrentTestNode>().LifeStyle.Transient);

        var f = windsor.Resolve<IRecurrentTestNodeFactory>();
        var root = f.Create(1);
        Assert.NotNull(root);
        Assert.AreEqual(1, root.Num);
        Assert.NotNull(root.Child);
        Assert.AreEqual(0, root.Child.Num);
        Assert.Null(root.Child.Child);
    }

It is failing with this exceptions:

Castle.MicroKernel.ComponentActivator.ComponentActivatorException : ComponentActivator: could not instantiate Tests.RecurrentTestNode
  ----> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
  ----> Castle.MicroKernel.CircularDependencyException : Dependency cycle has been detected when trying to resolve component 'Tests.RecurrentTestNode'.
The resolution tree that resulted in the cycle is the following:
Component 'Tests.RecurrentTestNode' resolved as dependency of
    component 'Tests.RecurrentTestNode' which is the root component being resolved.

It's obvious why such code could fail in case of services, but for factory it seems unnecessary restrictive. I'd like to left in factory variant because instead of plain int I have a bunch of container-resolved dependencies there.

Was it helpful?

Solution

Do it lazily to break the cycle, not in the constructor. Windsor's behaviour is correct.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top