简体   繁体   English

是否可以从autofac注册中排除构造函数?

[英]Is it possible to exclude a constructor from autofac registration?

If I have the following class, is it possible to exclude the copy constructor from Autofac registration? 如果我有以下类,是否可以从Autofac注册中排除复制构造函数?

public class A
{
    public A() {}
    public A(A other) { // copy constructor }
    public A(int b) { // some other stuff }
}

Basically, I would want autofac to resolve the default constructor, or if the user requested a Func<int, A> the third constructor. 基本上,我希望autofac解析默认构造函数,或者如果用户请求Func<int, A>第三个构造函数。 I never want autofac to resolve the copy constructor. 我从不希望autofac解析复制构造函数。 Is this possible? 这可能吗?

The reason for this is that when I try and use Autofac to inject a Func<A> , it results in a circular dependency as Autofac is trying to use the second constructor (it thinks it knows a way to resolve A, but the way to resolve A requires an A). 原因是当我尝试使用Autofac注入Func<A> ,它会导致循环依赖,因为Autofac正在尝试使用第二个构造函数(它认为它知道解决A的方法,但是解决A需要A)。

You can implement your own constructor selector that ignores your second constructor: 您可以实现自己的构造函数选择器 ,忽略您的第二个构造函数:

public class AConstructorSelector : IConstructorSelector
{
    public ConstructorParameterBinding SelectConstructorBinding(ConstructorParameterBinding[] constructorBindings)
    {
        if (constructorBindings == null) throw new ArgumentNullException("constructorBindings");
        if (constructorBindings.Length == 0) throw new ArgumentOutOfRangeException("constructorBindings");

        if (constructorBindings.Length == 1)
            return constructorBindings[0];

        var withLength = constructorBindings
            .Where(b => !b.TargetConstructor.GetParameters().Select(p => p.ParameterType).Contains(typeof(A)))
            .Select(binding => new { Binding = binding, ConstructorParameterLength = binding.TargetConstructor.GetParameters().Length })
            .ToArray();

        var maxLength = withLength.Max(binding => binding.ConstructorParameterLength);

        var maximal = withLength
            .Where(binding => binding.ConstructorParameterLength == maxLength)
            .Select(ctor => ctor.Binding)
            .ToArray();

        if (maximal.Length == 1)
            return maximal[0];

        throw new DependencyResolutionException("Unable to find constructor");
    }
}

And when register your class use it as parameter of the UsingConstructor 注册您的类时,请将其用作UsingConstructor参数

var builder = new ContainerBuilder();
builder.RegisterType<A>().UsingConstructor(new AConstructorSelector());

See fiddle 小提琴

Autofac 3.x will automatically create Implicit Relationship Types , eg Func<A> , Lazy<B> , etc. However you can override the default by registering your own. Autofac 3.x将自动创建隐式关系类型 ,例如Func<A>Lazy<B>等。但是,您可以通过注册自己的默认值来覆盖默认值。

builder.Register<Func<int, A>>(c => (value) => { return new A(value); });

This is registering the Func<int, A> signature and instructing which constructor to use to create this. 这是注册Func<int, A>签名并指示使用哪个构造函数来创建它。

Try it out at .NET Fiddle, https://dotnetfiddle.net/CTFyo3 在.NET Fiddle上试一试, https: //dotnetfiddle.net/CTFyo3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM