2013-03-04 1 views
1

NInject를 사용하여 알려진 단일 고정 범위의 Foo 서비스 목록을 해결하려고합니다. 이 해결 방법은 FooProvider의 생성자에서 발생합니다. 문제는 각 Foo가이 공급자를 필요로한다는 것입니다.Ninject를 사용하여 서비스를 확인할 때 스택 오버플로가 발생했습니다.

public interface IFoo { } 
public interface IFooProvider { } 

public class Foo : IFoo 
{ 
    private readonly IFooProvider _provider; 

    public Foo(IFooProvider provider) 
    { 
     _provider = provider; 
    } 
} 

public class FooProvider : IFooProvider 
{ 
    private List<IFoo> _allFooServices; 

    public FooProvider(IKernel kernel) 
    { 
     _allFooServices = kernel.GetAll<IFoo>().ToList(); 
    } 
} 

public class Program 
{ 
    private static void Main(string[] args) 
    { 
     var IoC = new StandardKernel(); 

     IoC.Bind<IFoo>().To<Foo>().InSingletonScope(); 
     IoC.Bind<IFooProvider>().To<FooProvider>().InSingletonScope(); 

     var foo = IoC.Get<IFoo>(); 
    } 
} 

논리적 순환 루프가 여기에 있으며 분명히 스택 오버플로로 인해 스택 오버플로가 표시됩니다. 그러나, 나는 싱글 톤에 바인딩 된 인터페이스를 가지고있다.

그것에 대해 생각해보십시오. 우리는 IFoo를 해결하려고 노력합니다. IFoo의 목록을 필요로하는 IFooProvider의 해결책이 필요합니다 ... 그러나 우리는 여전히 IFoo의 singleton을 해결하지 못했습니다.

어떻게이 문제를 해결할 수 있습니까?

[편집] 가능한 해결책; IFoo 서비스 인스턴스의 지연 버퍼링.

public FooProvider(IKernel kernel) 
{ 
    _kernel = kernel; 
} 

public IFoo Find(object context) 
{ 
    if (_allFooServices == null) 
     _allFooServices = _kernel.GetAll<IFoo>().ToList(); 

    return _allFooServices.Where(... 

[이유는?]

일반적인 생각 나는 그것이 안티 패턴으로 설명 보았 듯이, 서비스 로케이터 패턴을 방지하는 것입니다. 따라서 런타임 중에 종속성 인젝터를 통해 서비스를 해결하기보다는, 설치 중에 서비스 목록을 얻으려고합니다. 그러나이 문제는 서비스가 다른 서비스를 찾고자 할 때 위와 같은 문제가 있다는 것입니다.

+1

왜 'Foo'는'FooProvider'의 인스턴스를 필요로합니까? 실제로'FooProvider'가'Foo'를 생성하는 팩토리라면 다른 방법으로도 쉽게 사용할 수 있습니까? –

+0

모든 Foo가 서비스이므로 FooProvider는 주입 시간에 모든 Foo 서비스 목록을 얻으려고합니다. foo가 런타임 중에 다른 foo (컨텍스트에만 해당)를 찾아야 할 경우 런타임에 FooProvider에 요청할 수 있습니다. –

+0

'FooProvider'는 다른 모든'Foo'에 의한 의존성 삽입을 통해 쉽게 해결되는 싱글 톤이 아니어야합니까? –

답변

1

당신은 Ninject에이 순환 종속성을 확인할 수 없습니다. 이러한 객체 그래프를 손으로 만들 수도 없습니다.

먼저 최소한 하나의 생성자에서 순환 종속성을 제거해야합니다. 이 종속성을 특성으로 이동하고 특성 주입을 사용할 수 있습니다.

public class Foo : IFoo 
{ 
    [Inject] 
    public IFooProvider Provider { get; set; } 
} 

당신이 FooProvider의 생성자에서 IKernel에 종속성을 제거하고 대신 등록 IFoo 구현의 콜렉션의 주입을 사용한다 서비스 로케이터 패턴을 피하십시오.

public class FooProvider : IFooProvider 
{ 
    private List<IFoo> _allFooServices; 

    public FooProvider(IEnumerable<IFoo> fooServices) 
    { 
     _allFooServices = fooServices.ToList(); 
    } 
} 
0

정말이게 나쁜 디자인 인 것 같지만 직접 질문에 대답하기 위해 생성자에서 _allFooServices를 인스턴스화하지 마십시오. 다음과 같이 할 수 있습니다.

private List<IFoo> _allFooServices; 
private List<IFoo> AllFooServices 
{ 
    get { return _allFooServices ?? (_allFooServices = Kernel.GetAll<IFoo>().ToList()) } 
} 

아마도 Foo보다는 더 구체적인 예를 선택할 수 있습니다.

+0

일반적인 생각은 서비스 로케이터 패턴을 피하는 것입니다. 서비스 패턴 패턴을 안티 패턴으로 묘사했기 때문입니다. 따라서 런타임 중에 종속성 인젝터를 통해 서비스를 해결하기보다는, 설치 중에 서비스 목록을 얻으려고합니다. 그러나이 문제는 서비스가 다른 서비스를 찾고자 할 때 위와 같은 문제가 있다는 것입니다. –

+0

당신이 여기서 무엇을 얻고 있는지 확실하지 않습니다. 코드가 여전히 서비스 로케이터 패턴을 사용합니다. 단지 생성자 내에서 패턴을 사용하는 것입니다. 실제로 서비스 로케이터의 문제점을 피할 수는 없지만 실제로 발견하면 더 많은 문제가 발생합니다. – cbp

1

속성 주입 중 하나와 함께 사용할 수 있습니다.

public interface IFoo 
{ 
} 

public interface IFooProvider 
{ 
} 

public class Foo : IFoo 
{ 
    [Inject] 
    public IFooProvider Provider { get; set; } 
} 

public class FooProvider : IFooProvider 
{ 
    private List<IFoo> _allFooServices; 

    public FooProvider(IKernel kernel) 
    { 
     _allFooServices = kernel.GetAll<IFoo>().ToList(); 
    } 
} 

private static void Main(string[] args) 
{ 
    var IoC = new StandardKernel(); 
    IoC.Bind<IFoo>().To<Foo>().InSingletonScope(); 
    IoC.Bind<IFooProvider>().To<FooProvider>().InSingletonScope(); 

    var foo = IoC.Get<IFoo>(); 
} 
관련 문제