2

我正在尝试构建一个命令处理器,它可以接受任何实现标记接口(或者可能来自基类)的命令。处理器将处理它被要求处理的命令。但是,我正在努力解决真正的泛型类型,因为 Resolve(Type) 返回一个对象。如果可能的话,我不确定如何投射这个?

public void Process(ICommand command)
{
    var c = command.GetType();
    var t = typeof(ICommandHandler<>).MakeGenericType(new[] { c });
    var o = container.Resolve(t);
    //((ICommandHandler)o).Handle(command);  *** This doesn't work
}

调用代码将是这样的 -

Dispatcher.Process(new SomeCommand(Guid.NewGuid(),"Param1",12345));
4

2 回答 2

3

如果您绝对必须调用该ICommandHandler<T>.Handle方法并且您对系统的设计没有其他控制权,那么反射可能是您唯一的选择。没有很好的方法来处理从通用到非通用的转换。

否则,您可能有几个选择。

首先,如果你Dispatcher.Process可以通用,你可以保存所有的铸件。

public static class Dispatcher
{
  public static void Process<T>(T command) where T : ICommand
  {
    var handler = container.Resolve<ICommandHandler<T>>();
    handler.Handle(command);
  }
}

对于我在野外看到的此类问题,这是一个非常常见的解决方案。

如果你不能这样做,那么你可以让你的ICommandHandler<T>接口实现一个非通用的ICommandHandler基本接口

public interface ICommandHandler
{
  void Handle(ICommand command);
}

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

在后一种情况下,您必须切换强类型命令处理程序实现以调用相同的内部逻辑进行通用或基本处理,否则您将根据调用获得不同的处理,这将是不好的:

public class SomeCommandHandler : ICommandHandler<SomeCommand>
{
  public void Handle(ICommand command)
  {
    var castCommand = command as SomeCommand;
    if(castCommand == null)
    {
      throw new NotSupportedException("Wrong command type.");
    }
    // Hand off to the strongly-typed version.
    this.Handle(castCommand);
  }

  public void Handle(SomeCommand command)
  {
    // Here's the actual handling logic.
  }
}

然后,当您解决强类型ICommandHandler<T>转换时ICommandHandler(如您的问题的示例代码所示)将起作用。

这也是一个非常常见的解决方案,但我在泛型可用之前存在的系统中看到了更多,其中正在添加更新的 API。

但是,在这里的所有情况下,问题实际上不在于 Autofac 正在返回一个对象。这是一个影响任何泛型到非泛型转换方案的类/类型设计问题。

于 2012-09-10T15:06:56.510 回答
2

使用反射 - 但这是解决这个问题的最佳方法吗?

    public void Process(Command command)
    {
        var c = command.GetType();
        var ot = typeof(ICommandHandler<>);
        var type = ot.MakeGenericType(new[] { c });
        var mi = type.GetMethod("Handle");
        var o = container.Resolve(type);
        mi.Invoke(o, new object[] { command });
    }
于 2012-09-09T13:55:19.443 回答