2012-12-21 2 views
8

"Autofac은 컨테이너에서 얻을 수있는 대부분의 매개 변수를 사용하여 생성자를 자동으로 선택합니다." 그렇지 않으면 기본 생성자를 대신 선택해야합니다.매개 변수없는 자동 생성자 선택

internal class ParameterlessConstructorSelector : IConstructorSelector 
{ 
    #region Implementation of IConstructorSelector 

    /// <summary> 
    /// Selects the best constructor from the available constructors. 
    /// </summary> 
    /// <param name="constructorBindings">Available constructors.</param> 
    /// <returns> 
    /// The best constructor. 
    /// </returns> 
    public ConstructorParameterBinding SelectConstructorBinding(ConstructorParameterBinding[] constructorBindings) 
    { 
     return constructorBindings.First(); 
    } 

    #endregion 
} 

I 클래스를 연결 http://code.google.com/p/autofac/wiki/Autowiring, 내가 이런 짓을 :

(가) 먼저 constructorBindings 목록에 바인딩 항상 paremeterless 생성자와 하나
builder.RegisterType<EmployeeFactory>() 
     .As<IEmployeeFactory>().UsingConstructor(new ParameterlessConstructorSelector()) 
     .SingleInstance(); 

. 처음에 정의했는지 또는 autofac이 생성자를 검사하는 방법인지는 모르지만 이것이 매개 변수없는 생성자에 대한 올바른 접근 방법입니까?

감사

답변

6

Autofac 내부적으로 생성자를 검색 할 Type.GetConstructors 방법을 사용합니다. 방법 documentation 가입일

:

그러한 선언 순서 등의 특정 순서 생성자를 반환하지 않는 GetConstructors 방법. 순서가 달라 지므로 코드에서 반환되는 생성자 순서에 따라 을 의존해서는 안됩니다.

그래서 귀하의 경우에 First() 함께 일한 것을 단지 행운이었다. 적절한 구현에서 명시 적으로 0 인수 생성자를 검색해야합니다

public class DefaultConstructorSelector : IConstructorSelector 
{ 
    public ConstructorParameterBinding SelectConstructorBinding(
     ConstructorParameterBinding[] constructorBindings) 
    { 
     var defaultConstructor = constructorBindings 
      .SingleOrDefault(c => c.TargetConstructor.GetParameters().Length == 0); 
     if (defaultConstructor == null) 
      //handle the case when there is no default constructor 
      throw new InvalidOperationException();     
     return defaultConstructor; 
    } 
} 

당신이 매우 간단한 클래스와 이론을 테스트 할 수 있습니다 구현으로

public class MyClass 
{ 
    public readonly int i; 

    public MyClass(int i) 
    { 
     this.i = i; 
    } 

    public MyClass() 
    { 
     i = 1; 
    } 
} 

:

var builder = new ContainerBuilder(); 
// register 22 for each integer constructor argument 
builder.Register<int>(v => 22); 

builder.RegisterType<MyClass>().AsSelf() 
    .UsingConstructor(new ParameterlessConstructorSelector()); 
var c = builder.Build(); 
var myClass = c.Resolve<MyClass>(); 
Console.WriteLine(myClass.i); 

22을 출력합니다. 예를 들어 int 인수가있는 생성자는

입니다. 내 구현

:

//... 
builder.RegisterType<MyClass>().AsSelf() 
    .UsingConstructor(new DefaultConstructorSelector()); 
//... 
var myClass = c.Resolve<MyClass>(); 
Console.WriteLine(myClass.i); 

그것은 출력 1 예컨대 기본 생성자가 호출된다.

+0

처음에는 행운이었습니다.() :) 자세한 설명을 읽어 주셔서 감사합니다. –

+0

'InvalidOperationException' 대신 Autofac에 매개 변수없는 ctor가없는 경우에 더 적합한'DependencyResolutionException' 클래스가 추가되었습니다. – aholmes

1

기본 생성자를 명시 적으로 명시 적으로 등록하는 것이 더 간단하지 않습니까? Autofac의 최신 버전으로

builder.Register<EmployeeFactory>(c => new EmployeeFactory()) 
    .As<IEmployeeFactory>() 
    .SingleInstance(); 
+1

예,이 간단한 경우에 사용할 수 있습니다. 그러나 한 번에 여러 유형을 등록하는 경우 (예 : 'RegisterAssemblyTypes') 사용자 정의'IConstructorSelector '를 구현하는 것이 더 깔끔한 솔루션입니다. – nemesv

+5

최신 버전의 Autofac에는 적절한 유형의 생성자를 선택하는 UsingConstructor (params Type [] 매개 변수) 오버로드가 있습니다. 매개 변수없이 호출하면 기본 생성자가 선택됩니다. – Alexander

1

, 이것은 매우 간단하다 : 매개 변수없이

builder.RegisterType<EmployeeFactory>() 
     .As<IEmployeeFactory>().UsingConstructor() 
     .SingleInstance(); 

"UsingConstructor"를 호출

는 "매개 변수가없는 생성자를 사용하여"를 의미한다. https://autofac.org/apidoc/html/EB67DEC4.htm 및 관련 페이지를 참조하십시오.

관련 문제