Dynamic keyword does not work with IoC, but classic reflection

I did a little CQRS API for our system. I tried to replace some reflection code using a dynamic keyword, but it does not work.

Each command handler is a common CommandHandler<TCommand> using the void Execute(TCommand Command) method

With reflection he works

 public void Invoke(Contracts.Commands.Command command) { var handlerType = types[command.GetType()]; var handler = kernel.Get(handlerType); var method = handlerType.GetMethod("Execute"); method.Invoke(handler, new object[] { command }); } 

Kernel.Get is an untyped version of kernel.Get<T> in our IoC (Ninject). It works and the general method of performing T lights

This code fails with the exception of argument mismatch

 public void Invoke(Contracts.Commands.Command command) { var handlerType = types[command.GetType()]; dynamic handler = kernel.Get(handlerType); handler.Execute(command); } 

If I statically declare a type that it works with dynamic

 dynamic handler = new TestCommandHandler(); handler.Execute(new TestCommand()); 

edit: Additional information to answer questions in the comments

  • handlerType is a concrete class that implements the abstract class CommandHandler<TCommand> where TCommand : Command
  • The execute method is declared in an abstract class as public virtual void Execute(TCommand command)
  • TestCommand implements an abstract class command
  • The strange thing is that the same handler and command work if I statically declare them strongly typed, the last example (in the real world example, I have dependencies in the constructor, although

    edit2

  • Stacktrace

in CallSite.Target (Closure, CallSite, Object, Command) in System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2 [T0, T1] (CallSite site, T0 arg0, T1 arg1) with XXX.Business.Command.CommandHandlerInvoker.Invoke (Command command) at C: \ XXX.Business \ Command \ CommandHandlerInvoker.cs: line 29 at XXX.Web.XXXService.Execute (command command) at C: \ XXX.Web \ ExfiService.svc.cs: line 29 at XXX.Web.Controllers .ComplianceController.XXX (XXXViewModel viewModel) in C: \ XXX.Web \ Controllers \ XXXController.cs: line 52 in lambda_method (Closure, ControllerBase, Object []) in System.Web.Mvc.ActionMethodDispatcher.Execute (ControllerBase controller, object []) System.Web.Mvc.ReflectedActionDescriptor.Execute (ControllerContext controllerContext, IDictionary 2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary 2 parameters c) with System.Web.Mvc.ControllerActionInvoker <. > C_DisplayClass15.b_12 () in System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter (IActionFilter filter, ActionExecutingContext preContext, continued Func`1)

  • Exception

Best overloaded method matching for XXX.Business.Command.CommandHandler<XXX.Contracts.Commands.TestCommand>.Execute(XXX.Contracts.Commands.TestCommand)' has some invalid arguments

The error message indicates the abstract class T is not a specific class, but handlerType in the above code is a specific class

+4
source share
1 answer

You need to change your code to look like this:

 public void Invoke(Contracts.Commands.Command command) { var handlerType = types[command.GetType()]; dynamic handler = kernel.Get(handlerType); dynamic cmd = command; handler.Execute(cmd); } 

Note that the command parameter is first assigned to a dynamic local variable ( cmd ). This allows you to evaluate the type of cmd at runtime and maintain a dynamic call to Execute ; where, as NOT doing it this way, it is assumed that the Execute method has a fixed signature Execute(Contracts.Commands.Command command)

+3
source

Source: https://habr.com/ru/post/1443225/


All Articles