通用协变铸造或铸造到真实类型

时间:2012-05-30 10:48:39

标签: c# generics reflection cqrs

尝试构建CQRS解决方案,我有以下代码尝试查找Handler,然后调用Handle()方法。

下面的代码有效但当我们知道所有IHandleCommand<>时使用反射很烦人有一个Handle方法,这可以在编译时解决,我相信!

我是否必须以某种方式使用dynamic

public void SendCommand(Command command)
{
    Type handlerType = typeof(IHandleCommand<>).MakeGenericType(command.GetType());
    object handler = container.Resolve(handlerType);
    handler.GetType().GetMethod("Handle").Invoke(handler, new object[] { command });
}

这是上面使用的其他类型

public class Command {}

public class MyCommand : Command {}

public interface IHandleCommand<T>
{
void Handle(T command);
}

public class MyCommandHandler : IHandleCommand<MyCommand>
{
    public void Handle(MyCommand command)   {}
}

3 个答案:

答案 0 :(得分:0)

我做了一些类似于我使用容器(在我的例子中是StructureMap)来从中获取处理程序实例的东西。

查看该问题及其答案:StructureMap register generic types against all possible concrete implementations

答案 1 :(得分:0)

我使用Autofac来解决问题。
这是我最终的结果

假设这个界面

public interface IHandleCommand<T> where T : Command
{
  void Handle(T command);
}

Servicebus会调用类似的东西

private readonly IComponentContext container;

public InProcessBus(IComponentContext container)
{
  this.container = container;
}

public void Send<T>(T command) where T : Command
{
  if (command == null) throw new ArgumentNullException("Command");
  container.Resolve<IHandleCommand<T>>().Handle(command);
}

和我的Autofac CommandsHandlersModule

public class CommandsHandlersModule : Autofac.Module
{
  protected override void Load(ContainerBuilder builder)
  {
     builder.RegisterAssemblyTypes(typeof(CartCommandsHandler).Assembly)
       .AsClosedTypesOf(typeof(IHandleCommand<>))
       .SingleInstance();
   }
}

比你的应用程序打电话

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new CommandsHandlersModule());

答案 2 :(得分:0)

在玩完之后我发现了一些解决方案:

dynamic handler = container.Resolve(handlerType);
handler.Handle(command as dynamic);

但是如果我将命令作为动态发送到泛型方法,我会得到Command,因为它的真实类型为T来做魔术。也可以在编译时解析对Handle()的调用。然后就不需要通用的协变铸造,从一开始就证明是问题。

public void SendCommand(Command command)
{
    Invoke(command as dynamic);
}

private void Invoke<T>(T command) where T : Command
{
    var handler = container.Resolve<IHandleCommand<T>>();
    handler.Handle(command);
}

这真的很好,但由于我没有注册命令处理程序,所以我不会完全使用该解决方案,我将使用它:

private void Invoke<T>(T command) where T : Command
{
    Type handlerType = CommandToHandlerType(command);
    var handler = (IHandleCommand<T>)container.Resolve(handlerType);
    handler.Handle(command);
}

CommandToHandlerType()只是在程序集中搜索实现T的IHandleCommand的类型