代码之家  ›  专栏  ›  技术社区  ›  bielu000

没有从…的隐式引用转换。。。通用查询处理程序cqrs

  •  0
  • bielu000  · 技术社区  · 7 年前

    我想创建一个通用的查询处理程序(以及将来的命令处理程序),它可以处理每个查询,并在处理后返回查询结果。

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

    当然还有节目。cs类(我正在使用控制台应用程序进行测试)

    class Program
    {
        static void Main(string[] args)
        {
            var bus = new QueryBus();
            var query = new BrowseTitlesQuery();
    
            bus.Resolve<BrowseTitlesQueryHandler>(query);
    
        }
    }
    

    在我看来,它应该有效,但它没有。

    “CQR”类型。BrowsetTitlesQueryHandler不能用作泛型类型或方法“QueryBus”中的类型参数“T”。解决(IQuery)”。不存在来自“CQR”的隐式引用转换。BrowsetTitlesQueryHandler“到”cqrs。IQueryHandler’。[cqrs]

    为什么?

    2 回复  |  直到 7 年前
        1
  •  4
  •   poke    7 年前

    你有问题 co- and contravariance

    让我们先看看协方差一: BrowseTitlesQueryHandler 机具 IQueryHandler<BrowseTitlesQuery, IEnumerable<string>> Execute IEnumerable<string> . 然而,在 QueryBus ,您正在等待 T IQueryHandler<IQuery, object> 返回值为 object .

    为了允许 IQueryHandler<TQuery, TResult> 被抛弃 IQueryHandler<TQuery, object> 这个 TResult 参数需要为 . 这很简单,因为实际上 因此,使it协变是正确的做法(请注意 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);
    
        2
  •  0
  •   Sefe    7 年前

    您必须在查询总线上扩展类型参数:

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