如何在Funq IoC中解决循环依赖?

时间:2012-09-06 13:59:17

标签: c# ioc-container servicestack circular-dependency funq

我有两个课程,我需要互相参考。

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

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

当我这样做时:

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

当我尝试解析任一接口时,我得到一个循环依赖图,导致无限循环。有没有一种简单的方法可以在Funq中解决这个问题,或者您知道一种解决方法吗?

6 个答案:

答案 0 :(得分:6)

你可以随时(在所有容器中,我会说)依赖Lazy作为依赖,这将产生所需的结果。在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>());

答案 1 :(得分:1)

你的问题的答案是否定的,没有简单的方法。鉴于上面的代码,不可能构造没有 Funq的类,因此没有理由期望Func能够做到。

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

当然,如果你有IFooIBar的另一个实现没有依赖关系,或者你重构了,那么它可能是有可能的。

答案 2 :(得分:1)

一般来说,“在执行依赖注入时如何分解循环引用”这一问题的答案是:“使用属性注入”。

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) {}
}

使用Funq我认为这将是注册此依赖项的方法。

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

此外,我同意蒂姆罗杰斯的评论。当你有一个循环依赖,你的设计可能有一个问题,你应该看看它。这并不总是错的,但往往是错的。但是,您展示的代码非常抽象,我们无法就此提供任何反馈。

答案 3 :(得分:0)

这对我有用:

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; }
    }
}

修改
同样的想法,但在构造函数中没有副作用:

// 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。但我同意蒂姆罗杰斯的观点 - 循环参考是一个需要解决的问题。

答案 4 :(得分:0)

在容器中注册类型后,将容器作为静态变量使用:

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()
  {
  }

}

答案 5 :(得分:0)

我有一个类似的场景,两个班级之间的依赖关系使我意识到他们实际上应该合并为一个班级。