2014-09-24 3 views
5

Unity 컨테이너로 놀았으며 이상한 행동을 발견했습니다. 하나 이상의 인터페이스를 구현하는 클래스가 있습니다. 이 클래스를 다른 수명의 응용 프로그램에서 서로 다른 위치에서 사용하기를 원합니다. 그래서 IFooDerived1을 Foo에 Singleton으로 매핑하고 IFooDerived2를 Foo에 Transient로 매핑했습니다. 그러나 Foo의 등록은 Foo의 이전 등록을 손상시킵니다.LifetimeManager와 Unity RegisterType의 이상한 동작

샘플 :

interface IFoo { } 
    interface IFooDerived1 { } 
    interface IFooDerived2 { } 
    class Foo : IFoo, IFooDerived1, IFooDerived2 { } 

    static void Main(string[] args) 
    { 
     var container = new UnityContainer(); 

     container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager()); 
     container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager()); 
     container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager()); 

     foreach(var r in container.Registrations) 
     { 
      Console.WriteLine("{0} -> {1} : {2}", r.RegisteredType.Name, r.MappedToType.Name, r.LifetimeManagerType.Name); 
     } 
    } 

출력 :

IFoo -> Foo : TransientLifetimeManager 
    IFooDerived1 -> Foo : TransientLifetimeManager 
    IFooDerived2 -> Foo : TransientLifetimeManager 

이 올바른 행동인가? 아무도 논리적 인 설명을 줄 수 있습니까? 나는 다른 접근법을 쉽게 사용할 수 있으며, 왜 이런 일이 일어나는지 이해하고 싶습니다. 감사.

+0

Unity의 걱정스러운 동작 외에도, IFooDerived2가 다른 구현을 제공하는 동작을 추출해야한다고 생각하기 때문에 디자인을 살펴볼 수도 있습니다. 새로운'FooDerived2' 구현은'IFoo'에 의존 할 수 있습니다. – Steven

+0

예, 맞습니다. 디자인이 좋지 않습니다. 나는 이미 '진짜'코드를 수정했다. – boades

+0

하지만 나는 당신과 동의합니다, 이것은 '흥미로운'행동입니다. – Steven

답변

1

다음에 등록을 변경하는 경우 :

container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager()); 
container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager()); 
container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager()); 

다음과 같은 출력을 얻을 것이다 :

IFoo -> Foo : ExternallyControlledLifetimeManager 
    IFooDerived1 -> Foo : ExternallyControlledLifetimeManager 
    IFooDerived2 -> Foo : ExternallyControlledLifetimeManager 

WAT을? 어떤 추상화를 가져 오더라도 항상 동일한 인스턴스를 얻을 수 있습니다. 따라서 등록 순서를 변경하면 라이프 스타일의 동작이 완전히 달라집니다.

btw, ExternallyControlledLifetimeManagerweak reference to the object을 사용하고 더 이상 응용 프로그램이 참조를 유지하지 않아서 다시 만들 수 있기 때문에 무서운 것입니다. 이 라이프 스타일을 거의 사용하지 않아야합니다.

나는 이것에 대해 머리를 쓰려고 노력하고있다.하지만 Unity에서 등록 할 때 실제로 특정 라이프 스타일로 구현을 등록하고 있으며 제공된 추상화는 해당 등록과 매핑됩니다. 그것은 다음과 같은 일이 일어나고 있는지 더 분명해진다,

MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); 
MapToEntry(from: typeof(IFoo), to: typeof(Foo)); 

그래서 '대안'API와 : 우리가 통일을위한 대안 API를 정의한다면, 등록이 것 같은 것을하게

MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); 
MapToEntry(from: typeof(IFoo), to: typeof(Foo)); 
MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); 
MapToEntry(from: typeof(IFooDerived1), to: typeof(Foo)); 
MakeEntry(typeof(Foo), new TransientLifetimeManager()); 
MapToEntry(from: typeof(IFooDerived2), to: typeof(Foo)); 

즉, 동일한 Foo에 대한 세 개의 항목이 있으며 Unity가이 항목을 자동으로 수락하고 마지막 호출이 승리하는 것입니다. 이 암묵적인 행동을 싫어하지 마시오?

아마도 다른 라이브러리로 전환 할 시간은 언제입니까?

+0

흥미로운 분석이지만 실제로 질문에 대답하지 않습니다 ... –

+0

@ThomasLevesque I 알아 :-) – Steven

+0

No.이 동작은 매우 유용합니다. –