2011-09-26 3 views
2

이것은 Configuring an Autofac delegate factory that's defined on an abstract class의 후속 질문입니다. 나는 그의 대답했다 @Aren IIndex<K,V>를 사용하는 제안을 구현했지만, 나는 다음과 같은 오류를 극복 할 수 없어요 :Autofac이 IIndex를 통해 키 등록에 관한 질문을 해결합니다

Test method IssueDemoProject.WidgetTest.ProblemIllustration threw exception: Autofac.Core.DependencyResolutionException: None of the constructors found with 'Public binding flags' on type 'IssueDemoProject.WidgetWrangler' can be invoked with the available services and parameters: Cannot resolve parameter 'IssueDemoProject.WidgetType widgetType' of constructor 'Void .ctor(Autofac.IComponentContext, IssueDemoProject.WidgetType)'.

UPDATE : 내가 다른 구체적인 클래스를 등록하면 기반 주목해야한다 작동하는 매개 변수 아래 두 번째 테스트를 참조하십시오.

다음은이 문제를 설명하는 몇 가지 샘플 코드입니다. [편집 : IIndex 조회를 사용하기 위해 동일하게 업데이트했습니다.]

누군가 내가 뭘 잘못하고 있다고 말할 수 있습니까?

using Autofac; 
using Autofac.Features.Indexed; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace IssueDemoProject 
{ 

public enum WidgetType 
{ 
    Sprocket, 
    Whizbang 
} 

public class SprocketWidget : Widget 
{ 
} 

public class WhizbangWidget : Widget 
{ 
} 

public abstract class Widget 
{ 
} 

public class WidgetWrangler : IWidgetWrangler 
{ 
    public Widget Widget { get; private set; } 

    public WidgetWrangler(IComponentContext context, WidgetType widgetType) 
    { 
     var lookup = context.Resolve<IIndex<WidgetType, Widget>>(); 
     Widget = lookup[widgetType]; 
    } 
} 

public interface IWidgetWrangler 
{ 
    Widget Widget { get; } 
} 

[TestClass] 
public class WidgetTest 
{ 
    // NOTE: This test throws the exception cited above 
    [TestMethod] 
    public void ProblemIllustration() 
    { 
     var container = BuildContainer(
      builder => 
       { 
        builder.RegisterType<WidgetWrangler>().Keyed<IWidgetWrangler>(WidgetType.Sprocket). 
         InstancePerDependency(); 
        builder.RegisterType<WidgetWrangler>().Keyed<IWidgetWrangler>(WidgetType.Whizbang). 
         InstancePerDependency(); 
       } 
      ); 

     var lookup = container.Resolve<IIndex<WidgetType, IWidgetWrangler>>(); 
     var sprocketWrangler = lookup[WidgetType.Sprocket]; 
     Assert.IsInstanceOfType(sprocketWrangler.Widget, typeof(SprocketWidget)); 

     var whizbangWrangler = container.ResolveKeyed<IWidgetWrangler>(WidgetType.Whizbang); 
     Assert.IsInstanceOfType(whizbangWrangler.Widget, typeof(WhizbangWidget)); 
    } 

    // Test passes 
    [TestMethod] 
    public void Works_with_concrete_implementations() 
    { 
     var container = BuildContainer(
      builder => 
       { 
        builder.RegisterType<SprocketWidget>().Keyed<Widget>(WidgetType.Sprocket). 
         InstancePerDependency(); 
        builder.RegisterType<WhizbangWidget>().Keyed<Widget>(WidgetType.Whizbang). 
         InstancePerDependency(); 
       }); 

     var lookup = container.Resolve<IIndex<WidgetType, Widget>>(); 
     var sprocketWrangler = lookup[WidgetType.Sprocket]; 
     Assert.IsInstanceOfType(sprocketWrangler, typeof(SprocketWidget)); 

     var whizbangWrangler = container.ResolveKeyed<Widget>(WidgetType.Whizbang); 
     Assert.IsInstanceOfType(whizbangWrangler, typeof(WhizbangWidget)); 
    } 

    private IComponentContext BuildContainer(Action<ContainerBuilder> additionalRegistrations) 
    { 
     var assembly = GetType().Assembly; 
     var builder = new ContainerBuilder(); 
     builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces(); 
     builder.RegisterAssemblyTypes(assembly).AsSelf(); 
     additionalRegistrations(builder); 
     IComponentContext container = builder.Build(); 
     return container; 
    } } 
} 

답변

3

나는이 잘못에 대해 생각하고 있습니다. 주로 WidgetWrangler은 공장 (IIndex<,>)이 실제로 공장이 될 것으로 예상하고 있기 때문에 주로 WidgetType입니다.

예외WidgetType enum에 Autofac에 기본 등록이 없으므로 예외가 될 수 있습니다. Autofac은 당신이 WidgetWrangler을 지우기 위해 Autofac을 사용하려한다고 생각할 때 생성자에 전달할 값을 알아낼 수 없습니다.

Autofac에서 문제를 해결하려면 Autofac의 등록부에서 전체적으로 해결할 수있는 생성자가 하나 이상 있어야합니다. 그렇지 않으면 변수를 명시 적으로 해결 작업에 전달할 때 생성자를 하나 이상 포함해야합니다 (이 방법은 반사적이어서 매우 느립니다) .

이 모든 것의 목표는 어딘가에 WidgetType이 주어진 Widget의 새 하위 클래스를 검색하는 것입니다. 이 경우, 당신이 필요로하는 것은 IIndex<,>입니다.

새로운 위젯을 만들려면 어디든지 IIndex <,> 유형을 사용해야합니다. 간단 해.

인스턴스화와 함께 다른 작업을 수행해야하는 경우 IIndex를 사용하는 팩토리 클래스에서 IIndex를 래핑 한 다음 작업을 수행해야합니다. 예를 들어

: 당신은 그럼 그냥 단순히 포장 공장에서 사용 할 수

class Widget 
{ 
    // Stuff... 

    public virtual void Configure(XmlDocument xmlConfig) 
    { 
     // Config Stuff 
    } 
} 

interface IWidgetFactory 
{ 
    Widget Create(WidgetType type, XmlDocument config); 
} 

class WidgetFactory : IWidgetFactory 
{ 
    private readonly IIndex<WidgetType, Widget> _internalFactory; 
    public WidgetFactory(IIndex<WidgetType, Widget> internalFactory) 
    { 
     if (internalFactory == null) throw new ArgumentNullException("internalFactory"); 
     _internalFactory = internalFactory; 
    } 

    public Widget Create(WidgetType type, XmlDocument config) 
    { 
     Widget instance = null; 
     if (!_internalFactory.TryGetValue(type, out instance)) 
     { 
      throw new Exception("Unknown Widget Type: " + type.ToString); 
     } 

     instance.Configure(config); 

     return instance; 
    } 
} 

: 당신이 다시 Widget 인스턴스를 얻을 이외의 아무것도 할 필요가없는 경우,

class SomethingThatNeedsWidgets 
{ 
    private readonly IWidgetFactory _factory; 
    public SomethingThatNeedsWidgets(IWidgetFactory factory) 
    { 
     if (factory == null) return new ArgumentNullException("factory"); 
     _factory = factory; 
    } 

    public void DoSomething() 
    { 
     Widget myInstance = _factory.Create(WidgetType.Whizbang, XmlDocument.Load("config.xml")); 

     // etc... 
    } 
} 

가 기억을, IIndex<WidgetType, Widget>은 자체 공장입니다. (등록 된 모든 Widget 하위 클래스가 등록 된 경우 InstancePerDependency이라고 가정합니다. 그렇지 않으면 인스턴스 선택 자입니다

+0

내가 잘못 생각했습니다. 자세한 답변을 입력 해 주셔서 감사합니다. 잘못되어 가고 있습니다. 정말 고마워요! – neontapir

관련 문제