Search code examples
c#listautofaccommand-patterndependency-resolver

Commands can not be solved with Autofac when stored in a List


If have the code below, implementing the command pattern. I want to store several commands in a list and afterwards pick them from the list, resolve a commandhandler and finally execute the command.

When implementing this I ran into the problem, that resolving a single command worked from Autofac but resolving commands stored in the list raised an exception telling me the commandhandler could not be found even when it's the same command as I resolve the commandhandler before.

    public static void ShowResolveProblem()
    {
        var action = new DisplayMessageAction("Hello");
        var actionhandler = GetActionHandler(action); // this works well

        var actions = new List<IAction>();
        actions.Add(action);
        actionhandler = GetActionHandler(actions[0]); // this throws exception
    }

And this is the resolving method

    private static IActionHandler<T> GetActionHandler<T>(T action) where T : IAction
    {
        var container = GetActionHandlerContainer();

        return container.Resolve<IActionHandler<T>>();
    }

Does anyone know how to get this running?


Solution

  • If you don't have the concrete type while resolving your actionHandler, you can get it using typeof(IActionHandler<>).MakeGenericType(action.GetType()).

    To use your IActionHandler<T> without T you will have to create a new IActionHandler interface :

    class Program
    {
        static void Main(string[] args)
        {
            ContainerBuilder builder = new Autofac.ContainerBuilder();
            builder.RegisterAssemblyTypes(typeof(IActionHandler<>).Assembly)
                   .AsClosedTypesOf(typeof(IActionHandler<>));
    
            IContainer container = builder.Build();
    
            List<IAction> actions = new List<IAction>();
            actions.Add(new DisplayMessageAction("Test1"));
            actions.Add(new DisplayMessageAction("Test2"));
            actions.Add(new BeepMessageAction(200, 200));
    
            foreach (IAction action in actions)
            {
                Type actionHandlerType = typeof(IActionHandler<>).MakeGenericType(action.GetType()); 
                IActionHandler actionHandler = (IActionHandler)container.Resolve(actionHandlerType);
                actionHandler.Execute(action);
            }
        }
    }
    
    public interface IAction { }
    public interface IActionHandler
    {
        void Execute(IAction action);
    }
    public interface IActionHandler<T> : IActionHandler
        where T : IAction
    {
        void Execute(T IAction);
    }
    
    public abstract class ActionHandlerBase<T> : IActionHandler<T>
        where T : IAction
    {
        void IActionHandler.Execute(IAction action)
        {
            this.Execute((T)action);
        }
    
        public abstract void Execute(T IAction);
    }
    
    public class DisplayMessageAction : IAction
    {
        public DisplayMessageAction(String message)
        {
            this._message = message;
        }
    
        private readonly String _message;
    
        public String Message
        {
            get
            {
                return this._message;
            }
        }
    }
    public class DisplayMessageActionHandler : ActionHandlerBase<DisplayMessageAction>
    {
        public override void Execute(DisplayMessageAction action)
        {
            Console.WriteLine(action.Message);
        }
    }
    
    public class BeepMessageAction : IAction
    {
        public BeepMessageAction(Int32 frequency, Int32 duration)
        {
            this._frequency = frequency;
            this._duration = duration;
        }
    
        private readonly Int32 _frequency;
        private readonly Int32 _duration;
    
        public Int32 Frequency
        {
            get
            {
                return this._frequency;
            }
        }
        public Int32 Duration
        {
            get
            {
                return this._duration;
            }
        }
    }
    public class BeepMessageActionHandler : ActionHandlerBase<BeepMessageAction>
    {
        public override void Execute(BeepMessageAction action)
        {
            Console.Beep(action.Frequency, action.Duration);
        }
    }