4

我有一个实现命令模式的 WCF 服务。使用反射,我创建了一个字典,其中键是命令类型,值是 CommandHandler。这个想法是从 WCF 接收命令,使用字典获取处理程序类型,然后使用激活器创建处理程序的实例。

    public CommandResponse RunCommand(Command command)
    {
        _logger.Trace("Running Command");
        var handlerType = HandlerMap[command.GetType()];

        var handler = (AbstractCommandHandler<>)Activator.CreateInstance(handlerType);

        handler.HandleCommand(command);
        return new PostStatCommandResponse();

    }

public class StatCommandHandler : AbstractCommandHandler<PostStatCommand>
{

    public override void HandleCommand(PostStatCommand command)
    {

    }
}

问题是 Activator.CreateInstance 返回一个对象,而不是强类型命令处理程序。我需要能够调用 HandleCommand,但不知道如何将其转换为基本 AbstractCommandHandler<>

// Syntax error.  Gotta provide type to generic
(AbstractCommandHandler<>)Activator.CreateInstance(handlerType);

// Casting error at run time
(AbstractCommandHandler<Command>)Activator.CreateInstance(handlerType);

// This is dumb and defeats the purpose.
(AbstractCommandHandler<PostStatCommand>)Activator.CreateInstance(handlerType);

帮助?

4

3 回答 3

3

OR Mapper 对我正在实现的接口说了什么,他击败了我,您可以将泛型类型转换为此然后调用该方法。

  Command c = new PostStatCommand();
  var genericType = typeof(AbstractCommandHandler<>).MakeGenericType(c.GetType());
  ICommandHandler handler = (ICommandHandler)Activator.CreateInstance(genericType);
  handler.HandleCommand(c);

使 AbstractCommandHandler 实现 ICommandHandler

 public class AbstractCommandHandler<T> : ICommandHandler
  {
    public void HandleCommand(Command c)
    {
    }
  }

现在应该工作

于 2012-08-31T13:55:16.357 回答
2

为什么不直接HandleCommand通过反射调用?

var handler = Activator.CreateInstance(handlerType);
handlerType.GetMethod("HandleCommand").Invoke(handler, new [] {command});

或者,创建一个非泛型基类(接口也可以):

public abstract class AbstractCommandHandler
{
    public abstract void HandleCommand(Command command);
}

public abstract class AbstractCommandHandler<T> : AbstractCommandHandler
{
    public override void HandleCommand(Command command)
    {
        HandleCommand((T) command);
    }

    public abstract void HandleCommand(T command);
}

public class StatCommandHandler : AbstractCommandHandler<PostStatCommand>
{

    public override void HandleCommand(PostStatCommand command)
    {

    }
}

并在您的RunCommand方法中:

var handler = Activator.CreateInstance(handlerType);
((AbstractCommandHandler)handler).HandleCommand(command);
于 2012-08-31T13:37:58.483 回答
1

最好的可能性是提供一个使用Command并让您的AbstractCommandHandler<>类实现该接口的接口。像这样的东西:

public interface ICommandHandler
{
    void HandleCommand(Command command);
}

为什么?因为传递一个CommandtoHandleCommand是你唯一可以保证的事情。如果在设计时命令类型未知,则无法根据它检查参数值。因此,编译器不会让您将任何内容转换为AbstractCommandHandler<>.

换句话说,类型的参数T不会Command因为你省略了类型的实际类型参数而神奇地变成。它只是未指定。另请注意,AbstractCommandHandler<PostStatCommand>不是该类型的AbstractCommandHandler<>变量,因此无法分配给该类型的变量。

于 2012-08-31T13:44:25.590 回答