简体   繁体   English

通用协变强制转换或强制转换为实型

[英]Generic covariant cast or cast to real type

Trying to build a CQRS solution, I have the following code trying to find a Handler and then invoke a Handle() method. 尝试构建CQRS解决方案时,我有以下代码尝试找到Handler,然后调用Handle()方法。

The code below works but it's annoying to use reflection when we know that all IHandleCommand<> have a Handle method, this could be resolved at compiletime, I belive! 下面的代码有效,但是当我们知道所有IHandleCommand <>都有Handle方法时,使用反射很烦人,我相信这可以在编译时解决!

Do I have to use dynamic in some way? 我必须以某种方式使用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 });
}

Here's the other types used above 这是上面使用的其他类型

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)   {}
}

I made something similar to that where I used a container (StructureMap in my case) to get handler instances from. 我做了一些类似于使用容器(在本例中为StructureMap)从中获取处理程序实例的操作。

Check out that question and its answers: StructureMap register generic types against all possible concrete implementations 查看该问题及其答案: StructureMap针对所有可能的具体实现注册通用类型

I used Autofac to solve the problem. 我用Autofac解决了这个问题。
Here is what I ended up with 这就是我最终得到的

Assuming this interface 假设这个介面

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

The Servicebus will call something like this 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);
}

and my Autofac CommandsHandlersModule 和我的Autofac CommandsHandlersModule

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

Than from your app you call 比您通过应用调用

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

After playing around I found out some solutions: 玩了之后,我发现了一些解决方案:

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

But if I send command as dynamic to a generic method I will get Command as it's real type as T to do magic with. 但是,如果我以动态方式将命令发送给泛型方法,我将获得Command,因为它是T的实类型,可以用来处理魔术。 Also the call to Handle() can be resolved at compile time. 同样,对Handle()的调用也可以在编译时解决。 Then there's no need for generic covariant casting, which turns out to be problem from the beginning. 然后就不需要泛型协变转换,这从一开始就成为问题。

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);
}

It is really nice, but I won't go entirely for that solution since I don't registrate command handlers, i'll use this: 确实很好,但是由于我不提供命令处理程序,因此我不会完全采用该解决方案,我将使用以下命令:

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

CommandToHandlerType() just searches an assembly for a type implementing IHandleCommand of T CommandToHandlerType()只是在程序集中搜索实现T的IHandleCommand的类型

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM