我有一个实现命令模式的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);
帮助?
答案 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<>
的子类,因此无法分配给该类型的变量。