没有来自...通用查询处理程序 cqrs 的隐式引用转换
There is no implicit reference conversion from... generic query handler cqrs
我想创建一个通用的查询处理程序(以及未来的命令处理程序),它可以处理每个查询并在处理后,returns 查询结果。
IQueryHandler 接口:
public interface IQueryHandler
{
}
public interface IQueryHandler<TResult> : IQueryHandler
{
TResult Execute();
}
public interface IQueryHandler<TQuery, TResult> : IQueryHandler
where TResult : class
where TQuery: class
{
TResult Execute(TQuery query);
}
IQuery接口(标记接口):
public interface IQuery
{
}
简单查询对象:
public class BrowseTitlesQuery : IQuery
{
public string Title { get; set; }
}
简单查询处理程序对象:
public class BrowseTitlesQueryHandler : IQueryHandler<BrowseTitlesQuery, IEnumerable<string>>
{
public IEnumerable<string> Execute(BrowseTitlesQuery query)
{
throw new System.NotImplementedException();
}
}
查询总线
public class QueryBus
{
public object Resolve<T>(IQuery query)
where T: IQueryHandler<IQuery, Object>, IQueryHandler, new()
{
return new T().Execute(query);
}
}
当然还有Program.cs class(我正在使用控制台应用程序进行测试)
class Program
{
static void Main(string[] args)
{
var bus = new QueryBus();
var query = new BrowseTitlesQuery();
bus.Resolve<BrowseTitlesQueryHandler>(query);
}
}
在我看来它应该有效,但实际上无效。
我有以下错误:
The type 'cqrs.BrowseTitlesQueryHandler' cannot be used as type parameter 'T' in the generic type or method 'QueryBus.Resolve(IQuery)'. There is no implicit reference conversion from 'cqrs.BrowseTitlesQueryHandler' to 'cqrs.IQueryHandler'. [cqrs]
这是为什么?
这里 co- and contravariance 有问题。
让我们先看一下协方差:BrowseTitlesQueryHandler
实现了 IQueryHandler<BrowseTitlesQuery, IEnumerable<string>>
,所以 Execute
的 return 值是 IEnumerable<string>
。但是,在 QueryBus
中,您期望 T
为 IQueryHandler<IQuery, object>
,return 值为 object
。
为了允许 IQueryHandler<TQuery, TResult>
转换为 IQueryHandler<TQuery, object>
,TResult
参数需要 协变 。这在这里非常简单,因为它实际上 是 一个结果,所以使它协变是正确的做法(注意 out
):
public interface IQueryHandler<out TResult> : IQueryHandler
{ … }
public interface IQueryHandler<TQuery, out TResult> : IQueryHandler
{ … }
另一个问题有点困难,归结为 BrowseTitlesQueryHandler
需要 BrowseTitlesQuery
。但是 QueryBus.Resolve
只会给你一个一般的 IQuery
。这对于 BrowseTitlesQueryHandler
.
来说不够具体
不幸的是,解决这个问题的唯一方法是使查询类型也成为 Resolve
的通用类型参数:
public object Resolve<T, TQuery>(TQuery query)
where T : IQueryHandler<TQuery, object>, new()
where TQuery : class, IQuery
{
return new T().Execute(query);
}
现在,BrowseTitlesQueryHandler
获得了正确的查询参数并可以正确执行。当然,你需要调整你的调用:
bus.Resolve<BrowseTitlesQueryHandler, BrowseTitlesQuery>(query);
您必须在查询总线上扩展类型参数:
public class QueryBus
{
public object Resolve<THandler, TQuery, TResult>(TQuery query)
where T: IQueryHandler<TQuery, TResult>, IQueryHandler, new()
where TResult : class
where TQuery: class
{
return new THandler().Execute(query);
}
}
然后这样称呼它:
bus.Resolve<BrowseTitlesQueryHandler, BrowseTitlesQuery, IEnumerable<string>>(query);
我想创建一个通用的查询处理程序(以及未来的命令处理程序),它可以处理每个查询并在处理后,returns 查询结果。
IQueryHandler 接口:
public interface IQueryHandler
{
}
public interface IQueryHandler<TResult> : IQueryHandler
{
TResult Execute();
}
public interface IQueryHandler<TQuery, TResult> : IQueryHandler
where TResult : class
where TQuery: class
{
TResult Execute(TQuery query);
}
IQuery接口(标记接口):
public interface IQuery
{
}
简单查询对象:
public class BrowseTitlesQuery : IQuery
{
public string Title { get; set; }
}
简单查询处理程序对象:
public class BrowseTitlesQueryHandler : IQueryHandler<BrowseTitlesQuery, IEnumerable<string>>
{
public IEnumerable<string> Execute(BrowseTitlesQuery query)
{
throw new System.NotImplementedException();
}
}
查询总线
public class QueryBus
{
public object Resolve<T>(IQuery query)
where T: IQueryHandler<IQuery, Object>, IQueryHandler, new()
{
return new T().Execute(query);
}
}
当然还有Program.cs class(我正在使用控制台应用程序进行测试)
class Program
{
static void Main(string[] args)
{
var bus = new QueryBus();
var query = new BrowseTitlesQuery();
bus.Resolve<BrowseTitlesQueryHandler>(query);
}
}
在我看来它应该有效,但实际上无效。 我有以下错误:
The type 'cqrs.BrowseTitlesQueryHandler' cannot be used as type parameter 'T' in the generic type or method 'QueryBus.Resolve(IQuery)'. There is no implicit reference conversion from 'cqrs.BrowseTitlesQueryHandler' to 'cqrs.IQueryHandler'. [cqrs]
这是为什么?
这里 co- and contravariance 有问题。
让我们先看一下协方差:BrowseTitlesQueryHandler
实现了 IQueryHandler<BrowseTitlesQuery, IEnumerable<string>>
,所以 Execute
的 return 值是 IEnumerable<string>
。但是,在 QueryBus
中,您期望 T
为 IQueryHandler<IQuery, object>
,return 值为 object
。
为了允许 IQueryHandler<TQuery, TResult>
转换为 IQueryHandler<TQuery, object>
,TResult
参数需要 协变 。这在这里非常简单,因为它实际上 是 一个结果,所以使它协变是正确的做法(注意 out
):
public interface IQueryHandler<out TResult> : IQueryHandler
{ … }
public interface IQueryHandler<TQuery, out TResult> : IQueryHandler
{ … }
另一个问题有点困难,归结为 BrowseTitlesQueryHandler
需要 BrowseTitlesQuery
。但是 QueryBus.Resolve
只会给你一个一般的 IQuery
。这对于 BrowseTitlesQueryHandler
.
不幸的是,解决这个问题的唯一方法是使查询类型也成为 Resolve
的通用类型参数:
public object Resolve<T, TQuery>(TQuery query)
where T : IQueryHandler<TQuery, object>, new()
where TQuery : class, IQuery
{
return new T().Execute(query);
}
现在,BrowseTitlesQueryHandler
获得了正确的查询参数并可以正确执行。当然,你需要调整你的调用:
bus.Resolve<BrowseTitlesQueryHandler, BrowseTitlesQuery>(query);
您必须在查询总线上扩展类型参数:
public class QueryBus
{
public object Resolve<THandler, TQuery, TResult>(TQuery query)
where T: IQueryHandler<TQuery, TResult>, IQueryHandler, new()
where TResult : class
where TQuery: class
{
return new THandler().Execute(query);
}
}
然后这样称呼它:
bus.Resolve<BrowseTitlesQueryHandler, BrowseTitlesQuery, IEnumerable<string>>(query);