2012-12-21 176 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和相关页面。