Chr*_*hac 4 c# generics covariance contravariance c#-4.0
我想实现一些CommandBus可以做到的.DispatchCommandsCommandHandlers
Command是一个简单的DTO,描述了应该发生的事情.例如:"增量计数器减5"CommandHandler能够处理精确类型Command.CommandBus采取Command和执行CommandHandler即能处理它.我写的代码不编译.
编译器抱怨cannot convert from 'IncrementHandler' to 'Handler<Command>'.我不明白为什么,因为IncrementHandler实现Handler<Increment>和Increment实现Command
我已经尝试了通用接口上的两个in和out修饰符,它没有解决问题.
有没有办法只用接口来实现这个目标?
[TestClass]
public class CommandBusTest
{
[TestMethod]
public void DispatchesProperly()
{
var handler = new IncrementHandler(counter: 0);
var bus = new CommandBus(handler); // <--Doesn't compile: cannot convert from 'IncrementHandler' to 'Handler<Command>'
bus.Dispatch(new Increment(5));
Assert.AreEqual(5, handler.Counter);
}
}
public class CommandBus
{
private readonly Dictionary<Type, Handler<Command>> handlers;
public CommandBus(params Handler<Command>[] handlers)
{
this.handlers = handlers.ToDictionary(
h => h.HandledCommand,
h => h);
}
public void Dispatch(Command commande) { /*...*/ }
}
public interface Command { }
public interface Handler<TCommand> where TCommand : Command
{
Type HandledCommand { get; }
void Handle(TCommand command);
}
public class Increment : Command
{
public Increment(int value) { Value = value; }
public int Value { get; }
}
public class IncrementHandler : Handler<Increment>
{
// Handler<Increment>
public Type HandledCommand => typeof(Increment);
public void Handle(Increment command)
{
Counter += command.Value;
}
// Handler<Increment>
public int Counter { get; private set; }
public IncrementHandler(int counter)
{
Counter = counter;
}
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么,因为
IncrementHandler实现Handler<Increment>和Increment实现Command
让我们解决你的误解,其余的将变得清晰.
假设你想做的事情是合法的.出了什么问题?
IncrementHandler ih = whatever;
Handler<Command> h = ih; // This is illegal. Suppose it is legal.
Run Code Online (Sandbox Code Playgroud)
现在我们上课了
public class Decrement : Command { ... }
Run Code Online (Sandbox Code Playgroud)
现在我们将它传递给h:
Decrement d = new Decrement();
h.Handle(d);
Run Code Online (Sandbox Code Playgroud)
这是合法的,因为Handler<Command>.Handle需要a Command,而a Decrement是a Command.
所以发生了什么事?你刚刚通过递减命令ih,通过h,但是ih是一个IncrementHandler只知道如何处理的增量.
由于这是荒谬的,这里的某些东西必须是非法的; 您希望哪条线路非法?C#团队认为转换是非法的.
进一步来说:
您的程序在类型系统的安全检查中尝试使用反射,然后您抱怨当您编写不安全的东西时类型系统会阻止您.你为什么要使用泛型可言?
泛型(部分)是为了确保类型安全,然后您正在进行基于反射的调度.这没有任何意义; 不要采取措施增加类型安全性,然后做出英勇的努力来解决它们.
显然你希望解决类型安全问题,所以根本不要使用泛型.只需创建一个ICommand接口和一个Handler接受命令的类,然后有一些机制来解决如何分派命令.
我不明白的是为什么有两种东西.如果要执行命令,那么为什么不简单地将执行逻辑放在命令对象上?
除了基于类型的这种笨重的字典查找之外,还可以使用其他设计模式.例如:
命令处理程序可以有一个接受命令并返回布尔值的方法,处理程序是否可以处理此命令.现在你有一个命令处理程序列表,一个命令进来,你只是在列表中询问"你是我的处理程序吗?" 直到找到一个.如果O(n)查找太慢,则构建MRU缓存或记忆结果或某些此类事情,并且分摊的行为将得到改善.
调度逻辑可以放入命令处理程序本身.给命令处理程序一个命令; 它要么执行它,要么递归,调用它的父命令处理程序.因此,您可以构建一个命令处理程序图表,以便在必要时将工作推迟到彼此.(这基本上是QueryService在COM中的工作方式.)
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |