Unity의 Resolve () 메서드에 생성자 매개 변수를 전달할 수 있습니까?


92

종속성 주입을 위해 Microsoft의 Unity를 사용하고 있으며 다음과 같이하고 싶습니다.

IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);

RepositoryA그리고 RepositoryB모두가 사용하는 생성자가 IDataContext매개 변수를, 그리고 유니티 내가 그것을 통과하는 상황으로 저장소를 초기화 할 수 있습니다. 또한 IDataContextUnity에 등록되어 있지 않습니다 (의 인스턴스 3 개를 원하지 않음 IDataContext).

답변:


71

오늘부터 다음 기능을 추가했습니다.

여기에 최신 드롭입니다.

http://unity.codeplex.com/SourceControl/changeset/view/33899

여기에 대한 토론 :

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

예:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"



2
"클래스 'Microsoft.Practices.Unity.ParameterOverrides'에 형식 매개 변수가 없습니다." Unity 3.5를 사용하고 있습니다. 이 코드는 이전 버전의 Unity에만 유효합니까?
Thomas Levesque 2014

그것은 나를 위해 작동합니다. 참고 : 클래스에는 "name"매개 변수와 "address"매개 변수가있는 매개 변수화 된 생성자가 있어야합니다. Foo(string name, int address) { ... }
adun

Unity 2.1 사용 : container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
mrfelis

38

<2 센트>

나중에 컨텍스트보다 더 많거나 적은 다른 서비스를 사용하기로 결정하면 어떻게됩니까?

생성자 매개 변수 및 IoC의 문제는 매개 변수가 서비스 인터페이스가 정의하는 계약의 일부가 아닌 사용중인 구체적인 유형에 궁극적으로 연결된다는 것입니다.

제 제안은 컨텍스트를 해결하고 Unity가 3 개의 인스턴스를 생성하는 것을 피할 수있는 방법이 있어야한다고 생각하거나 객체를 생성하는 방법이있는 팩토리 서비스를 고려해야한다고 생각합니다.

예를 들어, 나중에 기존 데이터베이스에 전혀 의존하지 않고 대신 XML 파일을 사용하여 테스트 용 더미 데이터를 생성하는 저장소를 구성하기로 결정하면 어떻게 될까요? XML 콘텐츠를 해당 생성자에 어떻게 공급 하시겠습니까?

IoC는 디커플링 코드를 기반으로합니다. 인수의 유형과 의미를 구체적인 유형에 묶음으로써 실제로 디커플링을 제대로 수행하지 못했지만 여전히 종속성이 있습니다.

"이 코드는이 인터페이스를 구현하는 한 가능한 모든 유형의 저장소와 통신 할 수 있습니다 .... 아, 그리고 데이터 컨텍스트를 사용합니다."

이제 다른 IoC 컨테이너가이를 지원한다는 것을 알고 있으며 제 첫 번째 버전에서도 사용했지만 제 생각에는 해결 단계에 속하지 않습니다.

</ 2 센트>


3
귀하의 요점을 확인하고 귀하에게 동의하지만 RepositoryC와 다른 동일한 IDataContext를 갖기 위해서는 RepositoryA 및 RepositoryB의 인스턴스가 여전히 필요합니다. 또한 IRepositoryA 및 IRepositoryB에는 IDataContext에 대한 속성이 있습니다. 샘플 코드를 약간 업데이트하겠습니다.
NotDan 2009

2
좋은 지적입니다. 생성자에 문자열 매개 변수를 추가하려고했지만이 시점을 확인한 후 완전히 날아간 객체로 만들기로 결정했습니다. 그것은 단지이 시점에서 문자열로 구성,하지만 난 이미 내가 더 유용한 속성을 추가 할 수있는 방법을 볼 수 있습니다
산토 벤자민

9

고마워요 ... 내 게시물은 "Exist"의 게시물과 유사합니다. 아래를 참조하십시오.

        IUnityContainer container = new UnityContainer();
        container.LoadConfiguration();

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });

5

ResolvedParameter <T> ( "name") 내의 주입 아키텍처에 따라 InjectionConstructor / InjectionProperty / InjectionMethod를 사용하여 컨테이너에서 사전 등록 된 객체의 인스턴스를 가져올 수 있습니다.

귀하의 경우에는이 개체를 이름으로 등록해야하며 동일한 인스턴스에 대해 LifeTimeManager로 ContainerControlledLifeTimeManager ()가 필요합니다.

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");

  var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));

4
이 코드가 확실합니까? 그것은 컴파일되지 않습니다 ... Resolve의 컬렉션을 소요 ResolverOverride하고, InjectionConstructor하지 않은 것입니다 ResolverOverride.
Thomas Levesque 2014

네, 잘못된 것 같습니다. 단결이 그렇게 설계 했어야했지만. 매개 변수 이름이 모든 것을 변경하면
Frank Q.

3

아주 짧은 대답은 아니오입니다. Unity는 현재 내가 찾을 수있는 상수 또는 주입되지 않은 생성자에 매개 변수를 전달할 방법이 없습니다. IMHO는 빠진 가장 큰 단일이지만 누락이 아닌 디자인이라고 생각합니다.

Jeff Fritz가 언급했듯이 이론적으로는 다양한 유형에 삽입 할 컨텍스트 인스턴스를 알고있는 사용자 지정 수명 관리자를 만들 수 있지만 이는 처음에 Unity 또는 DI 사용 목적을 제거하는 것처럼 보이는 하드 코딩 수준입니다.

전체 DI에서 조금 뒤로 물러나서 저장소 구현이 자체 데이터 컨텍스트를 설정하도록 할 수 있습니다. 컨텍스트 인스턴스 는 여전히 컨테이너에서 확인할 수 있지만 사용할 항목을 결정하는 논리는 저장소 구현으로 이동해야합니다. 확실히 순수하지는 않지만 문제를 없앨 것입니다.


1

사용할 수있는 또 다른 대안은 두 개의 컨테이너를 만들고 각각에 대해 인스턴스를 등록하는 것입니다.

IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context


//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance

이것도 도움이되기를 바랍니다


0

NotDan, lassevk에 대한 의견에서 자신의 질문에 답변했을 수 있습니다.

먼저 LifetimeManager를 사용하여 Unity가 생성하는 IDataContext의 수명주기와 인스턴스 수를 관리합니다.
http://msdn.microsoft.com/en-us/library/cc440953.aspx

ContainerControlledLifetimeManager개체가 필요한 인스턴스 관리를 제공 하는 것처럼 들립니다 . LifetimeManager가 제자리에 있으면 Unity는 IDataContext 종속성이 필요한 모든 개체에 동일한 IDataContext 인스턴스를 추가해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.