4

相互に参照する必要がある 2 つのクラスがあります。

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

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

私がする時:

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

いずれかのインターフェイスを解決しようとすると、無限ループにつながる循環依存グラフが表示されます。Funq でこれを解決する簡単な方法はありますか、または回避策を知っていますか?

4

6 に答える 6

7

いつでも (そしてすべてのコンテナーで) 代わりに依存関係として Lazy に依存することができ、それによって望ましい結果が得られます。ファンクで:

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>());
于 2012-09-09T21:05:09.753 に答える
1

あなたの質問に対する答えはノーです。簡単な方法はありません。上記のコードを考えると、Funqなしでどちらのクラスも構築することは不可能であるため、Func がそれを実行できると期待する理由はありません。

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

もちろん、依存関係のない、または依存関係のない別の実装がある場合IFooIBarまたはリファクタリングした場合は、可能かもしれません。

于 2012-09-06T20:08:09.457 に答える
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;
});

さらに、Tim Rogers のコメントに同意します。依存関係が循環している場合は、おそらく設計に問題があるため、それを確認する必要があります。これは常に間違っているわけではありませんが、多くの場合間違っています。ただし、表示されているコードは非常に抽象的であり、それについてフィードバックを提供する方法はありません。

于 2012-09-07T22:00:02.410 に答える
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()
  {
  }

}
于 2012-09-07T08:43:53.427 に答える
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;
});

ps しかし、私は Tim Rogers に同意します - 循環参照は解決すべき問題です。

于 2012-09-06T15:29:19.097 に答える