简体   繁体   中英

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?

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. I never want autofac to resolve the copy constructor. 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).

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

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.

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.

Try it out at .NET Fiddle, https://dotnetfiddle.net/CTFyo3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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