2012-12-21 175 views
8

「Autofac自動選擇能夠從容器中獲取的參數最多的構造函數。」我希望它做其他事情,而不是選擇默認的構造函數。 http://code.google.com/p/autofac/wiki/AutowiringAutofac無參數構造函數選擇

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 
} 

當我接線類,我這樣做:

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

首先在constructorBindings列表綁定始終是一個與paremeterless構造。不知道它是第一次定義還是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 e.g默認的構造函數被調用。

+0

我知道我很幸運First():)感謝您的詳細解釋。 –

+0

現在Autofac沒有'InvalidOperationException',而是有一個'DependencyResolutionException'類,如果沒有找到無參數的ctor就更合適。 – aholmes

1

只是顯式註冊默認構造函數不是更簡單嗎?

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

是的,它可以適用於這種簡單的情況。但是,如果一次註冊多種類型(例如使用'RegisterAssemblyTypes'),實現自定義的'IConstructorSelector'就是更清晰的解決方案。 – nemesv

+5

最新版本的autofac具有UsingConstructor(params Type [] parameter)重載,它選擇具有適當類型的構造函數 - 如果調用時沒有參數,它將選擇默認構造函數。 – Alexander

1

隨着最新版本的Autofac的,這是非常簡單的:

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

呼喚 「UsingConstructor」 不帶任何參數表示 「使用參數的構造函數」。 請參閱https://autofac.org/apidoc/html/EB67DEC4.htm和相關頁面。