Autofac constructor chaining

208 views Asked by At

How would I implement the equivalent using Autofac to output 123.

I've had a look at the following but I don't think it quite fits in with what I'm trying to achieve.

http://docs.autofac.org/en/latest/advanced/adapters-decorators.html

Maybe someone can enlighten me - is this decorator?

using System;

namespace Prototypes.Decorator
{
    public class Program
    {
        static void Main()
        {
            new Class1(new Class2(new Class3(null))).Do();

            Console.ReadKey(true);
        }
    }

    public interface ICommand
    {
        void Do();
    }

    public abstract class BaseClass : ICommand
    {
        private readonly ICommand _command;

        protected BaseClass(ICommand command)
        {
            _command = command;
        }

        public abstract void Do();

        public void CallNext()
        {
            if (_command != null)
            {
                _command.Do();
            }
        }
    }

    public class Class1 : BaseClass
    {
        public Class1(ICommand command) : base(command)
        {
        }

        public override void Do()
        {
            Console.Write(1);

            CallNext();
        }
    }

    public class Class2 : BaseClass
    {
        public Class2(ICommand command) : base(command)
        {
        }

        public override void Do()
        {
            Console.Write(2);

            CallNext();
        }
    }

    public class Class3 : BaseClass
    {
        public Class3(ICommand command) : base(command)
        {
        }

        public override void Do()
        {
            Console.Write(3);

            CallNext();
        }
    }
}

For bonus points what if there was another interface on the base constructor. Something plausible like protected BaseClass(ICommand command, ILog log) { ... }

1

There are 1 answers

2
mrvux On BEST ANSWER

There are several ways to build your container in order to achieve what you need, you can use keyed services or lambdas.

Lambdas tend to be a bit less error prone than using strings , so here is a simple container registration that does what you need:

ContainerBuilder cbLambdas = new ContainerBuilder();
cbLambdas.Register<Class3>(ctx => new Class3(null));
cbLambdas.Register<Class2>(ctx => new Class2(ctx.Resolve<Class3>()));
cbLambdas.Register<Class1>(ctx => new Class1(ctx.Resolve<Class2>()));

IContainer containerLambda = cbLambdas.Build();
containerLambda.Resolve<Class1>().Do();

In case of adding ILog interface, as per the following declaration:

public interface ILog
{
    void Log();
}

public class NullLog : ILog
{
    public void Log() { }
}

And adding it as dependency (in that case only for Class2)

public class Class1 : BaseClass
{
    private readonly ILog logger;

    public Class1(ICommand command, ILog logger)
        : base(command)
    {
        this.logger = logger;
    }

    public override void Do()
    {
        Console.Write(1);
        CallNext();
    }
}

Then you registration becomes:

ContainerBuilder cbWithLog = new ContainerBuilder();
cbWithLog.RegisterType<NullLog>().As<ILog>();
cbWithLog.Register<Class3>(ctx => new Class3(null));
cbWithLog.Register<Class2>(ctx => new Class2(ctx.Resolve<Class3>()));
cbWithLog.Register<Class1>(ctx => new Class1(ctx.Resolve<Class2>(), ctx.Resolve<ILog>()));

IContainer containerLog = cbWithLog.Build();
containerLog.Resolve<Class1>().Do();