9

「Autofacは、コンテナーから取得できるパラメーターが最も多いコンストラクターを自動的に選択します。」それ以外の方法で実行し、代わりにデフォルトのコンストラクターを選択したいと思います。http://code.google.com/p/autofac/wiki/Autowiring

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リストの最初のバインディングは、常にパラメーターなしのコンストラクターを持つものです。それが最初に定義されたのか、autofacがコンストラクターをスキャンする方法なのかはわかりませんが、これはパラメーターなしのコンストラクターを配線するための正しいアプローチですか?

ありがとう

4

3 に答える 3

7

Autofac は、このType.GetConstructorsメソッドを内部的に使用してコンストラクターを検出します。

メソッドのドキュメントから:

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);

たとえば22int引数を持つコンストラクターが呼び出されます。

私の実装では:

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

たとえば1、デフォルトのコンストラクターが呼び出されます。

于 2012-12-21T14:42:57.970 に答える
2

デフォルトのコンストラクターを明示的に登録する方が簡単ではないでしょうか?

builder.Register<EmployeeFactory>(c => new EmployeeFactory())
   .As<IEmployeeFactory>()
   .SingleInstance();
于 2012-12-21T15:16:51.100 に答える