6

この質問はUnityコンテナに関するものですが、どの依存関係コンテナにも適用できると思います。

循環依存の2つのクラスがあります。

class FirstClass
{
    [Dependency]
    public SecondClass Second { get; set; }
}

class SecondClass
{
    public readonly FirstClass First;

    public SecondClass(FirstClass first)
    {
        First = first;
    }
}

技術的には、それらをシングルトンとして扱う場合、両方の依存関係をインスタンス化して正しく注入することが可能です。

var firstObj = new FirstClass();
var secondObj = new SecondClass(firstObj);
firstObj.Second = secondObj;

Unityで同じことをしようとすると、StackOverflowExceptionが発生します。

var container = new UnityContainer();
container.RegisterType<FirstClass>(new ContainerControlledLifetimeManager());
container.RegisterType<SecondClass>(new ContainerControlledLifetimeManager());

var first = container.Resolve<FirstClass>(); // StackOverflowException here!
var second = container.Resolve<SecondClass>(); // StackOverflowException here too!

Unityが部分的に初期化されたオブジェクトの使用から私を保護しようとしていることは理解していますが、この保護を義務ではなくオプションとして使用したいと考えています。

質問:現在の行動は不可能ですか?

4

3 に答える 3

5

単一性で循環依存関係を使用することはまったくできないと思います。

参照: http://msdn.microsoft.com/en-us/library/cc440934.aspx

于 2009-09-04T07:04:01.910 に答える
2

これを回避する 1 つの方法は、クラスの 1 つの依存関係に遅延読み込みを使用することです。

[TestFixture]
public class CircularUnityTest
{
    IUnityContainer container;

    [SetUp]
    public void SetUp()
    {
        container = new UnityContainer();
        container.RegisterType(typeof(ILazy<>), typeof(Lazy<>));
        container.RegisterType<FirstClass>(new ContainerControlledLifetimeManager());
        container.RegisterType<SecondClass>(new ContainerControlledLifetimeManager());
    }

    [Test]
    public void CanResolveFirstClass()
    {
        var first = container.Resolve<FirstClass>();
        Assert.IsNotNull(first);
    }

    [Test]
    public void CanResolveSecondClass()
    {
        var second = container.Resolve<SecondClass>();
        Assert.IsNotNull(second);
    }

    [Test]
    public void CanGetFirstFromSecond()
    {
        var second = container.Resolve<SecondClass>();
        Assert.IsNotNull(second.First);
    }
}

class FirstClass 
{
    [Dependency]
    public SecondClass Second { get; set; }
}

class SecondClass
{
    private readonly ILazy<FirstClass> lazyFirst;

    public FirstClass First { get { return lazyFirst.Resolve(); } }

    public SecondClass(ILazy<FirstClass> lazyFirst)
    {
        this.lazyFirst = lazyFirst;
    }
}

public interface ILazy<T>
{
    T Resolve();
}

public class Lazy<T> : ILazy<T>
{
    IUnityContainer container;

    public Lazy(IUnityContainer container)
    {
        this.container = container;
    }

    public T Resolve()
    {
        return container.Resolve<T>();
    }
}
于 2009-09-17T09:25:33.310 に答える
1

RegisterType の代わりに RegisterInstance を使用して、目標を達成できます。シングルトンと同じように動作し、Resolve が呼び出されるたびに同じインスタンスを使用します。次の例を見てください。

class FirstClass
{
    [Dependency]
    public SecondClass Second { get; set; }
}

class SecondClass
{
    public readonly FirstClass First;

    public SecondClass(FirstClass first)
    {
        First = first;
    }
}

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        var firstObj = new FirstClass();

        var secondObj = new SecondClass(firstObj);
        firstObj.Second = secondObj;

        // Register instance instead of type!!!
        container.RegisterInstance<FirstClass>(firstObj);
        container.RegisterType<SecondClass>();

        var first = container.Resolve<FirstClass>();
        var second = container.Resolve<SecondClass>(); 
    }
}

乾杯、

パベル

于 2009-09-18T11:09:53.050 に答える