4

I have two classes which I need to reference each other.

class Foo
{
    public Foo(IBar bar) {}
}

class Bar
{
    public Bar(IFoo foo) {}
}

When I do:

container.RegisterAutoWiredAs<Foo, IFoo>();
container.RegisterAutoWiredAs<Bar, IBar>();

and when I try to resolve either interface I get a circular dependency graph which results in an infinite loop. Is there an easy way to solve this in Funq or do you know of a workaround?

Rickard
  • 2,325
  • 13
  • 22

6 Answers6

7

You can always (and in all containers, I'd say) rely on Lazy as a dependency instead, and that would yield the desired result. In Funq:

public Bar(Lazy<IFoo> foo) ...
public Foo(Lazy<IBar> bar) ...

container.Register<IBar>(c => new Bar(c.LazyResolve<IFoo>());
container.Register<IFoo>(c => new Foo(c.LazyResolve<IBar>());
kzu
  • 1,795
  • 15
  • 16
1

The answer to your question is no, there is no easy way. Given the code above, it is impossible to construct either class without Funq, so there's no reason to expect Func to be able to do it.

var foo = new Foo(/* what do I pass here? */);
var bar = new Bar(foo);

Of course, if you had another implementation of either IFoo or IBar without the dependency, or you refactored, it might be possible.

Tim Rogers
  • 21,297
  • 6
  • 52
  • 68
1

In general, the answer to the question "how do I break up circular references when doing Dependency Injection" is: "use property injection".

class Foo
{
    public Foo() {}

    // Break the dependency cycle by promoting IBar to a property.
    public IBar Bar { get; set; }
}

class Bar
{
    public Bar(IFoo foo) {}
}

With Funq I think this would be the way to register this dependency.

container.Register<IBar>(c =>
{
    var foo = new Foo();
    var bar = new Bar(foo);
    foo.Bar = bar;
    return bar;
});

Furthermore, I agree with Tim Rogers' comment. When you have a circular dependency, there is probably a problem in your design, and you should take a look at it. This is not always wrong, but often is. However, the code you show is very abstract, and there is no way for us to give any feedback on that.

Steven
  • 166,672
  • 24
  • 332
  • 435
0

This works for me:

using Funq;
using NUnit.Framework;

namespace FunqIoCyclicReferenceTest
{
    [TestFixture]
    public class FunqIoCCyclicReferenceTest
    {
        [Test]
        public void Please_Work()
        {
            var container = new Container();
            container.Register<IBar>(c => new Bar());
            container.Register<IFoo>(c => new Foo(c.Resolve<IBar>()));

            var foo = container.Resolve<IFoo>();

            Assert.IsNotNull(foo);
        }
    }

    public class Foo : IFoo
    {
        public Foo(IBar bar)
        {
            bar.Foo = this;
            Bar = bar;
        }

        public IBar Bar { get; set; }
    }

    public interface IBar
    {
        IFoo Foo { get; set; }
    }

    public interface IFoo
    {
        IBar Bar { get; set; }
    }

    public class Bar : IBar
    {
        public IFoo Foo { get; set; }
    }
}

EDIT
Same idea but without side-effects in constructor:

// interfaces
public interface IBar
{
    IFoo Foo { get; set; }
}

public interface IFoo
{
    IBar Bar { get; set; }
}

// implementations
public class Foo : IFoo
{
    public IBar Bar { get; set; }
}    

public class Bar : IBar
{
    public IFoo Foo { get; set; }
}

// usage
container.Register<IBar>(c => new Bar());
container.Register<IFoo>(c => 
{
    var bar = c.Resolve<IBar>();
    var foo = new Foo();

    bar.Foo = foo;
    foo.Bar = bar;
});

p.s. but I do agree with Tim Rogers - circular reference is a problem to solve.

alex.b
  • 4,547
  • 1
  • 31
  • 52
  • nope, that won't make a difference. Resolving either interface will still make an infinite loop. Example: resolving IFoo will resolve IBar which will create a new Bar and try to resolve IFoo and we're back where we began and so on. – Rickard Sep 06 '12 at 17:17
  • this still doesn't change anything. When you resolve IFoo or IBar the container will go into an infinite loop. – Rickard Sep 06 '12 at 18:38
  • sure, but then we get a side effect in the Foo constructor which IMO is as much of a code smell as the circular dependency – Rickard Sep 07 '12 at 05:51
0

After registering your types in the container, make the container available as a static variable:

public static class ContainerHolder
{
   public static Container Container {get;set;}
}

public class Foo : IFoo
{
  private IBar _bar;

  public Foo(IBar bar)
  {
    _bar = bar;
  }
}

public class Bar : IBar
{
  private IFoo _foo
  {
    get { return ContainerHolder.Container.Resolve<IFoo>(); }
  }

  public Bar()
  {
  }

}
armen.shimoon
  • 6,303
  • 24
  • 32
  • sure, that's a workaround but its side stepping the whole point of DI. You've only introduced a static dependency which I have to fake in my unit test and make sure I restore the state after each test. don't like that – Rickard Sep 07 '12 at 09:02
  • Agreed. Perhaps you can do some refactoring, usually bad to have circular dependencies in the first place. Perhaps a Baz class that Foo and Bar both use? – armen.shimoon Sep 07 '12 at 09:46
0

I had a similar scenario and the dependency between the two classes made me realize they should actually be combined into a single class.

IUnknown
  • 559
  • 6
  • 12