创建通用实例

时间:2012-08-31 13:22:12

标签: c# generics

我有一个实现命令模式的WCF服务。使用反射,我创建了一个Dictionary,其中键是命令类型,值是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返回一个对象,而不是强类型的commandhandler。我需要能够调用HandleCommand,但无法弄清楚如何将它强制转换为基础AbstractCommandHandler&lt;&gt;

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

帮助?

3 个答案:

答案 0 :(得分:3)

O. R. 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)
    {
    }
  }

现在应该工作

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

答案 2 :(得分:1)

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

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

为什么呢?因为将Command传递给HandleCommand是唯一可以保证的事情。如果在设计时未知命令类型,则无法检查参数值。因此,编译器不允许您向AbstractCommandHandler<>投射任何内容。

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