我在玩cqs,我想在类库中实现它(所以没有IOC,IServiceProvider等)。这是我写的一些代码:
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
public class Query : IQuery<bool>
{
public int Value { get; set; }
}
public class QueryHandler : IQueryHandler<Query, bool>
{
public bool Handle(Query query)
{
return query.Value > 0;
}
}
public class Dispatcher
{
private readonly Dictionary<Type, object> handlers = new Dictionary<Type, object>();
public Dispatcher()
{
handlers.Add(typeof(Query), new QueryHandler());
}
public T Dispatch<T>(IQuery<T> query)
{
IQueryHandler<IQuery<T>, T> queryHandler;
if (!this.handlers.TryGetValue(query.GetType(), out object handler) ||
((queryHandler = handler as IQueryHandler<IQuery<T>, T>) == null))
{
throw new Exception();
}
return queryHandler.Handle(query);
}
}
这就是我如何调用我的代码:
Query query = new Query();
Dispatcher dispatcher = new Dispatcher();
var result = dispatcher.Dispatch(query);
但是问题在于,在调度程序内部,我不知道为什么不能将变量处理程序转换为
IQueryHandler<IQuery<T>,T>
。这里是一些额外的数据:PS:我知道如何使此功能(动态)生效,但是我想了解为什么此代码无法正常工作。
最佳答案
该代码不起作用,因为IQueryHandler
通用参数上的TQuery
是不变的。 TQuery
必须是协变的,以便handler
可转换为IQueryHandler<IQuery<T>, T>
,但这是不可能的,我将在后面解释。但是,您可以使TQuery
互变,这使您可以将handler
转换为IQueryHandler<ASubclassOfQuery, T>
。 TResult
可以是协变的。这是执行此操作的代码:
public interface IQueryHandler<in TQuery, out TResult> where TQuery : IQuery<TResult>
有关泛型方差的更多信息,请参见this page。
至于为什么
handler
不是IQueryHandler<IQuery<T>, T>
,我们首先假设它是,这意味着该代码可以编译:IQueryHandler<IQuery<T>, T> q = handler;
q.Handle(new MyQuery<T>());
MyQuery
的定义如下:class MyQuery<T> : IQuery<T> {}
但是,
handler
的运行时类型为QueryHandler
。 QueryHandler.Handle
仅处理Query
对象,而不处理MyQuery<T>
对象!我们有一个矛盾,因此我们对handler
是IQueryHandler<IQuery<T>, T>
的假设必须为假。关于c# - 与C#中的泛型类型有些混淆,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57918641/