【问题标题】:Generic covariant cast or cast to real type泛型协变转换或转换为真实类型
【发布时间】:2012-06-05 17:31:05
【问题描述】:

在尝试构建 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)   {}
}

【问题讨论】:

  • 烦人是什么意思?代码写好了..它的工作原理...
  • 当我认为有更好的方法时,通过反射调用 Handle() 让我很困扰。

标签: c# generics reflection cqrs


【解决方案1】:

我做了一些类似于我使用容器(在我的例子中是结构映射)来获取处理程序实例的地方。

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

【讨论】:

  • 很好的链接,我需要深入研究您的解决方案。
  • 我想我可以使用 void Execute(object command) 为处理程序实现一个非通用接口,但这并不理想。
【解决方案2】:

我使用 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());

【讨论】:

  • 我的 SendCommand() 是 WPF 操作,wpf 中不允许使用泛型,拥有 真的很有帮助。
【解决方案3】:

玩了一圈后,我找到了一些解决方案:

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

但是,如果我将命令作为动态命令发送到泛型方法,我将得到命令,因为它是真正的类型,如 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 的类型

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 2020-06-16
    • 2012-11-28
    • 1970-01-01
    相关资源
    最近更新 更多