如何在运行时解析泛型类型

时间:2012-09-09 11:08:36

标签: autofac

我正在尝试构建一个命令处理器,它可以接受任何实现标记接口的命令(或者可能来自基类)。处理器将处理要求处理的命令。但是我正在努力解决真正的泛型类型,因为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));

2 个答案:

答案 0 :(得分: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返回一个对象;这是一个类/类型设计问题,会影响任何泛型到非泛型转换方案。

答案 1 :(得分: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 });
    }