【问题标题】:Cast an Expression投射表达式
【发布时间】:2018-07-17 10:09:31
【问题描述】:

我有以下几点:

class Base
class Derived : Base
IQueryable<Derived> queryable = ???
Expression<Func<Base, bool>> filter = ???

我想用表达式过滤可查询的内容,并返回一个IQueryable&lt;Derived&gt;

但是,Expression 是不变的。这意味着queryable.Where(filter) 被推断为Where(this IQueryable&lt;Base&gt;, Expression&lt;Func&lt;Base, bool&gt;&gt;),并返回IQueryable&lt;Base&gt; 而不是IQueryable&lt;Derived&gt;

C# 不允许将 filter 转换为 Expression&lt;Func&lt;Derived, bool&gt;&gt;,并且将 Where 返回的 IQueryable&lt;Base&gt; 转换为 IQueryable&lt;Derived&gt; 在运行时失败。

解决这个问题的最佳方法是什么?

【问题讨论】:

    标签: c# iqueryable linq-expressions variance


    【解决方案1】:

    务实的解决办法是:

    var result = queryable.Where(filter).Cast<Derived>();
    

    你也可以通过重写表达式树来做到这一点,但是......这似乎不值得。但它有效:

    var typed = Expression.Lambda<Func<Derived, bool>>(
            filter.Body, filter.Parameters);
    var result = queryable.Where(typed); // IQueryable<Derived>
    

    【讨论】:

    • Cast 的运行时复杂度是多少(或者查询执行/强制结果时的运行时复杂度)?好像很浪费
    • @Martijn 随意测量它......我不知道;我猜这很大程度上取决于IQuerable&lt;T&gt; 的实现
    • oneliner private Expression&lt;Func&lt;A, B&gt;&gt; Upcast&lt;A, B, C, D&gt;(Expression&lt;Func&lt;C, D&gt;&gt; src) where A : C where D : B =&gt; Expression.Lambda&lt;Func&lt;A, B&gt;&gt;(src.Body, src.Parameters);也似乎很有魅力。感谢您制作的精彩柠檬水。
    • @Martijn 是的,只要您在谈论类和/或接口,那应该没问题;如果您添加结构,它会变得更加复杂,您可能需要将强制转换注入树体,这可能比您想要做的工作更多;可能值得为其中一些类型添加:class 约束,但是...嗯,这可能无关紧要
    • 我会尝试使用它。我宁愿有额外的声音而不是可能不健全的强制方法。具有向我承诺某些东西的签名但在运行时抛出异常的方法是 IMO 我可能拥有的最糟糕的事情。
    猜你喜欢
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多