2014-03-13 5 views
1

Castle Windsor를 사용하여 정수를 기록하는 클래스를 만들고 싶습니다. 하지만 다른 클래스와 함께 여러 번 꾸미고 싶습니다. 관련된 모든 Concret에 해결할 수있는 종속성이있는 경우 이것이 작동하는 방식을 볼 수 있지만 여기서는 그렇지 않습니다. ModelUpdatingRecorder가 아닌 선택적 종속성이 있기 때문에, IRecorder 여기서 일하지 않습니다 해결다른 생성자 인수가있는 장식 자

container.Register(Component.For<IRecorder>().ImplementedBy<NotifyingRecorder>()); 
container.Register(Component.For<IRecorder>().ImplementedBy<ModelUpdatingRecorder>()); 

:

public interface IRecorder 
{ 
    void Add(int value); 
} 

public class NotifyingRecorder : IRecorder 
{ 
    readonly IRecorder decoratedRecorder; 

    public NotifyingRecorder(IRecorder decoratedRecorder) 
    { 
     this.decoratedRecorder = decoratedRecorder; 
    } 

    public void Add(int value) 
    { 
     decoratedRecorder.Add(value); 
     System.Console.WriteLine("Added " + value); 
    } 
} 

public class ModelUpdatingRecorder : IRecorder 
{ 
    int seed; 

    public ModelUpdatingRecorder(int seed) 
    { 
     this.seed = seed; 
    } 

    public void Add(int value) 
    { 
     seed += value; 
    } 
} 

그리고 등록 :이 코드를 생각해 보자. seed은 컴파일시 알 수 없기 때문에 정적 종속성을 사용할 수 없습니다.

런타임에 seed 매개 변수를 지정하고 장식을 여전히 사용할 수 있습니까?

이 코드 샘플은 제 시나리오를 단순화 한 것이지만 아이디어는 같습니다. 필자는 데코레이터를 사용하고, 가장 낮은 디자이너는 데 이터/인스턴스를 제공해야한다.

+0

그래서 데코레이터를 제쳐두고 런타임에 종속성을 어떻게 제공하겠습니까? –

+0

@PhilDegenhardt 일반적으로 [Typed Factory Facility] (http://docs.castleproject.org/Default.aspx?Page=Typed-Factory-Facility-interface-based-factories&NS=Windsor)의 공장을 통해. –

+1

까지 런타임에서 비 선택적 종속성을 제공하는 것이 팩토리 메서드를 통해 수행 될 수도 있고 컨테이너를 연결하여 종속성이 일부 전역 (정적) 저장소를 통해 검색되도록 할 수도 있습니다. 내가 아는 한, 후자는 해결되는 구성 요소의 하위 종속성에 종속성이있는 경우 유일하게 사용 가능한 메커니즘입니다. 현명한 머리카락이 내 생각보다 더 낫다.이 질문을 관심과 함께 보게 될 것이다. –

답변

0

시드 (ISeedHolder?)에 시드를 래핑하고 싱글 톤 라이프 스타일로 등록 할 수 있습니다. 그런 다음 원시 int 대신 ModelUpdatingRecorder의 인터페이스를 사용하십시오. 당신의 씨앗 병렬 처리해야 할 수 있습니다하지 않는 한이 솔루션은 당신이 필요 달성겠습니까 ModelUpdatingRecorder

public interface ISeedHolder 
{ 
    int Seed {get;set;} 
} 

public class ModelUpdatingRecorder : IRecorder 
{ 
    int seed; 

    public ModelUpdatingRecorder(ISeedHolder seedHolder) 
    { 
     this.seed = seedHolder.Seed; 
    } 

를 구성 할 때 당신이 씨앗을 설정하고이를 해결할 수 있도록해야합니까?

+1

이것은 단지 문제를 방어합니다. 나는'ModelUpdatingRecord'에'ISeedHolder'의 특정 인스턴스 (즉, 특정 시드 값을 가진 인스턴스)를 주어야합니다. 그리고 이것을 수행하는 것은 원래의 질문과 같은 문제를 가지고 있습니다. –

+0

'ISeedHolder'가 싱글 톤으로 정의된다면, 어떤 데이터가'ModelUpdatingRecord'에 공급 될지에 대한 접근을 갖습니다. 그렇죠? – samy

+0

네,하지만 글로벌 컨텍스트는 제가 피하려고하는 것입니다. 나는 이들을 여러 스레드에서 생성 할 수 있으며, 관련된 작업을 단일 작업으로 조정하는 것은 내가 원하는 작업이 아닙니다. –

0

저는 이것이 수행되어야하는 방법이라고 믿는 해결책을 발견했습니다. Windsor의 내부에있는 DefaultDependencyResolver에는 RebuildContextForParameter이라는 하위 종속성 (위의 IRecorder 데코 레이팅 된 인스턴스)을 해결하는 방법이 있습니다. 이것은 의존성 (즉, 생성자에 대한 매개 변수)을 해석 할 때 사용할 새로운 컨텍스트를 생성하기 위해이를 호출합니다. 상기 방법은 :

/// <summary>This method rebuild the context for the parameter type. Naive implementation.</summary> 
protected virtual CreationContext RebuildContextForParameter(CreationContext current, Type parameterType) 
{ 
    if (parameterType.ContainsGenericParameters) 
    { 
     return current; 
    } 

    return new CreationContext(parameterType, current, false); 
} 

CreationContext 생성자에서 false 파라미터에 해당하여 서브 종속성 파라미터를 전달하는 current 문맥의 AdditionalArguments를 복사한다 propagateInlineDependencies이다. 그런 다음

public class DefaultDependencyResolverInheritContext : DefaultDependencyResolver 
{ 
    protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType) 
    { 
     if (parameterType.ContainsGenericParameters) 
     { 
      return current; 
     } 

     return new CreationContext(parameterType, current, true); 
    } 
} 

을 윈저 컨테이너를 만들 때 사용합니다 :

DefaultDependencyResolver에서 파생되는 새로운 클래스를 생성, false true이 플립

var kernel = new DefaultKernel(
       new DefaultDependencyResolverInheritContext(), 
       new NotSupportedProxyFactory()); 
var container = new WindsorContainer(kernel, new DefaultComponentInstaller()); 

NotSupportedProxyFactoryDefaultComponentInstaller이 기본값은 DefaultKernelWindsorContainer에 대해 매개 변수가없는 생성자를 사용할 때.

완료되면 위 코드는 공장을 사용하여 IRecorder을 만들 때 작동합니다. 즉,:

// during type registration/bootstrapping 
container.AddFacility<TypedFactoryFacility>(); 
container.Register(Component.For<IRecorder>().ImplementedBy<NotifyingRecorder>()); 
container.Register(Component.For<IRecorder>().ImplementedBy<ModelUpdatingRecorder>()); 
container.Register(Component.For<IRecorderFactory>().AsFactory()); 

IRecorderFactory이 경우 예상대로

public interface IRecorderFactory 
{ 
    IRecorder Create(int seed); 
} 

그런 다음이 작동 : 다른 사람을 도움이

IRecorderFactory recorderFactory = container.Resolve<IRecorderFactory>(); 
IRecorder recorder = recorderFactory.Create(20); 
recorder.Add(6); 

희망!

+0

패트릭 전에이 작품을 보았습니다. 이 경우 확실히 당신이 찾고있는 결과를 만들어 낼 것입니다. 문제는 해결 호출에 전달 된 매개 변수가 의도 한 종속성 측면에서 특정 적이 지 않다는 것입니다. 이들은 트리의 임의의 하위 종속성마다 선택적으로 사용할 수 있습니다. 복잡한 구성 요소/종속성 트리의 경우 위험한 부분이 큰 진흙탕이됩니다. –