Custom Constructor Selection

Most of the time, when registering reflection components, choosing the correct constructor to use can be safely left up to Autofac, or if required, a explicit constructor can be specified against the registration with UsingConstructor.

For advanced use-cases, you can implement custom behaviour to choose both the set of available constructors for a type, and which one to use of the available set.

FindConstructorsWith & IConstructorFinder

The FindConstructorsWith method on a registration allows you to specify how to determine the set of available constructors for a registration, either using a delegate to retrieve constructors from the Type:

// Find all private/internal constructors as well as public
builder.RegisterType<ComponentWithInternalConstructors>()
       .FindConstructorsWith(type => type.GetDeclaredConstructors());

or by implementing IConstructorFinder, which makes it easier to cache the found constructors for performance purposes:

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

// When registering...
builder.RegisterType<ComponentWithInternalConstructors>()
       .FindConstructorsWith(new AllConstructorsFinder());

Note

In the case of open generic registrations, the Type passed to either the FindConstructorsWith delegate or IConstructorFinder will be that of the concrete type, not the generic.

IConstructorSelector

Once the set of available constructors has been determined, each time the component is resolved, one of those constructors must be selected.

If there’s only one available constructor, we just use that one, but if there’s more than one available constructor, we have to decide which constructor is most suitable.

For this, we can implement the IConstructorSelector interface. Autofac’s default implementation of this interface (MostParametersConstructorSelector) chooses the constructor with the most parameters that are able to be obtained from the container at the time of resolve.

You can use a custom implementation of IConstructorSelector when the default Autofac behaviour is not suitable.

Here’s an abstract example of a constructor selector that allows a parameter to force use of the ‘first’ constructor.

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

You then register the selector against the component:

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

Note

Implementations of IConstructorSelector are only invoked if a given component has more than one available constructor.