Dynamically call a method on a generic target

后端 未结 2 834
旧时难觅i
旧时难觅i 2020-12-19 14:44

I have a generic interface ICommandHandler<> that will have a number of implementations each for processing a specific implementation of ICommand

相关标签:
2条回答
  • 2020-12-19 15:22

    Try this

    dynamic handler=Activator.CreateInstance(handlerType);
    try
      {
             handler.Handle((dynamic)command);
       }
    
       catch
       {
       // do whatever you want 
       }
    
    0 讨论(0)
  • 2020-12-19 15:43

    Most DI containers (including Ninject) allow you to do something like this:

    public void Dispatch<T>(T command) where T : ICommand
    {
        ICommandHandler<T> handler = IoC.Get<ICommandHandler<T>>();
        handler.Handle(command);
    }
    

    If you don't know the type of command (in other words, if typeof(T) != command.GetType()), using double-dispatch is the easiest way:

    class SomeCommand : ICommand
    {
        // ...
    
        public void Dispatch(IoC ioc)
        {
            var handler = ioc.Get<IHandle<SomeCommand>>();
            handler.Handle(this);
        }
    }
    

    but you could go with reflection if you find adding this code to all Commands distasteful.

    Edit Here is a reflection-based version. You can (and should) cache the compiled delegate.

    interface ICommand { }
    interface IHandle<TCommand> where TCommand : ICommand
    {
        void Handle(TCommand command);
    }
    
    class CreateUserCommand : ICommand { }
    class CreateUserHandler : IHandle<CreateUserCommand>
    {
        public void Handle(CreateUserCommand command)
        {
            Console.Write("hello");
        }
    }
    
    [TestMethod]
    public void build_expression()
    {
        object command = new CreateUserCommand();
        object handler = new CreateUserHandler();
    
        Action<object, object> dispatcher = BuildDispatcher(command.GetType());
        dispatcher(handler, command);
    }
    
    private static Action<object, object> BuildDispatcher(Type commandType)
    {
        var handlerType = typeof(IHandle<>).MakeGenericType(commandType);
        var handleMethod = handlerType.GetMethod("Handle");
    
        var param1 = Expression.Parameter(typeof(object));
        var param2 = Expression.Parameter(typeof(object));
    
        var handler = Expression.ConvertChecked(param1, handlerType);
        var command = Expression.ConvertChecked(param2, commandType);
        var call = Expression.Call(handler, handleMethod, command);
    
        var lambda = Expression.Lambda<Action<object, object>>(call, param1, param2);
        return lambda.Compile();
    }
    
    0 讨论(0)
提交回复
热议问题