项目
版本

Autofac 自定义构造函数选择

大多数情况下,在 注册反射组件 时,可以安全地将选择正确的构造函数的工作交给 Autofac,或者如果需要的话,可以通过 UsingConstructor 在注册中指定一个明确的构造函数。

对于高级用例,您可以实现自定义行为来选择类型可用的构造函数集以及使用其中的哪个构造函数。

FindConstructorsWith & IConstructorFinder

注册上的 FindConstructorsWith 方法允许您指定如何确定注册的可用构造函数集。这可以通过委托从 Type 中检索构造函数实现:

// 找到所有私有/内部构造函数以及公共构造函数
builder.RegisterType<ComponentWithInternalConstructors>()
       .FindConstructorsWith(type => type.GetDeclaredConstructors());

或者通过实现 IConstructorFinder 接口,这使得更容易为了性能考虑缓存找到的构造函数:

public class AllConstructorsFinder : IConstructorFinder
{
    private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> ConstructorCache = new();

    public ConstructorInfo[] FindConstructors(Type targetType)
    {
        var retval = ConstructorCache.GetOrAdd(targetType, t => t.GetDeclaredConstructors());

        if (retval.Length == 0)
        {
            throw new NoConstructorsFoundException(targetType);
        }

        return retval;
    }
}

// 注册时...
builder.RegisterType<ComponentWithInternalConstructors>()
       .FindConstructorsWith(new AllConstructorsFinder());

注意
对于泛型注册,传递给 FindConstructorsWith 委托或 IConstructorFinderType 将是具体类型,而不是泛型。

IConstructorSelector

一旦确定了可用的构造函数集,每次组件被解析时,必须从中选择一个构造函数。

如果只有一个可用构造函数,我们只需使用它;但如果有多于一个可用的构造函数,我们需要决定哪个构造函数最合适。

为此,我们可以实现 IConstructorSelector 接口。Autofac 的此接口的默认实现( MostParametersConstructorSelector )会选择在解析时可以从容器获取参数最多的构造函数。

当默认的 Autofac 行为不适合时,您可以使用自定义 IConstructorSelector 实现。

这里是一个抽象示例,说明了一个允许参数强制使用“第一个”构造函数的构造函数选择器。

public class FirstConstructorOverrideSelector : IConstructorSelector
{
    private IConstructorSelector _autofacDefault = new MostParametersConstructorSelector();

    public BoundConstructor SelectConstructorBinding(BoundConstructor[] constructorBindings, IEnumerable<Parameter> parameters)
    {
        if (parameters.Any(x => x is ConstantParameter p && string.Equals(p.Value, "use-first")))
        {
            return constructorBindings.First();
        }

        return _autofacDefault.SelectConstructorBinding(constructorBindings, parameters);
    }
}

然后,您可以在组件上注册该选择器:

builder.RegisterType<MyComponent>()
       .UsingConstructor(new FirstConstructorOverrideSelector());

注意
IConstructorSelector 实现仅在给定组件具有多个可用构造函数时才会被调用。

在本文档中