Search code examples
design-patternsdependency-injectionautofac

Autofac multiple implementation of same interface and implements are called in a if logic


I have an interface called ibaseinterface using which I have created 2 classes lets say baseclass1 and baseclass2.

Now I have a class named as top-level as below

public class toplevel
{
    public ibaseinterface selection(string selection)
    {
        int.TryParse(selection, out int sel);
        if (sel < 2)
            return new baseclass1();
        else
            return new baseclass2();
    }
}

based on user input I select the class that needs to be called. so how do I resolve the dependencies, in this case, using autofac.

Note: I definitely can't have different interfaces for the base classes.


Solution

  • In case you need to select an implementation based on some runtime data, the three typical solutions are:

    • The Proxy design pattern
    • The Adapter design pattern
    • The Factory design pattern.

    Here's an example of the factory design pattern:

    public interface IBaseInterfaceFactory
    {
        ibaseinterface selection(string selection);
    }
    
    public class toplevel
    {
        private readonly IBaseInterfaceFactory factory;
        public toplovel(IBaseInterfaceFactory factory) => this.factory = factory;
    
        public ibaseinterface selection(string selection)
        {
            return this.factory.selection(selection);
        }
    }
    
    // This class depends on Autofac and should therefore be placed near your Autofac
    // registations.
    internal class AutofacBaseInterfaceFactory : IBaseInterfaceFactory
    {
        private readonly IComponentContext context;
        public AutofacBaseInterfaceFactory(IComponentContext context) =>
            this.context = context;
    
        public ibaseinterface selection(string selection)
        {
            int.TryParse(selection, out int sel);
            if (sel < 2)
                return this.context.Resolve<baseclass1>();
            else
                return this.context.Resolve<baseclass2>();
        }
    }
    

    This can be wired up using the following code:

    builder.RegisterType<toplevel>().AsSelf();
    builder.RegisterType<AutofacBaseInterfaceFactory>().As<IBaseInterfaceFactory>();
    builder.RegisterType<baseclass1>().AsSelf();
    builder.RegisterType<baseclass2>().AsSelf();
    

    Note that in the case that toplevel's job is to just return a IBaseInterfaceFactory, in that cae toplevel already acts as the factory, and in that case it can be completely reduced from the equation.