【问题标题】:What I get from UnaryExpression.Operand?我从 UnaryExpression.Operand 得到什么?
【发布时间】:2019-01-27 14:11:47
【问题描述】:

我正在阅读关于如何building an IQueryable Provider的代码

下面是代码片段

internal class QueryTranslator : ExpressionVisitor
    {
        .....
        private static Expression StripQuotes(Expression e)
        {
            while (e.NodeType == ExpressionType.Quote)
            {
                e = ((UnaryExpression)e).Operand;
            }
            return e;
        }
        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            if (m.Method.DeclaringType == typeof(Queryable))
            {
                if (m.Method.Name == "Where")
                {
                    sb.Append("SELECT * FROM (");
                    this.Visit(m.Arguments[0]);
                    sb.Append(") AS T WHERE ");
                    LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]);
                    this.Visit(lambda.Body);
                    return m;
                }
                else if (m.Method.Name == "Select")
                {
                    LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]);
                    ColumnProjection projection = new ColumnProjector().ProjectColumns(lambda.Body, this.row);
                    sb.Append("SELECT ");
                    sb.Append(projection.Columns);
                    sb.Append(" FROM (");
                    this.Visit(m.Arguments[0]);
                    sb.Append(") AS T ");
                    this.projection = projection;
                    return m;
                }
            }
            throw new NotSupportedException(string.Format("The method '{0}' is not supported", m.Method.Name));
        }
        .....
    }

我无法理解 StripQuotes 方法,我从 e = ((UnaryExpression)e).Operand 得到什么?

【问题讨论】:

  • 操作数是给操作员的值,例如,如果我做!false,操作数是false,同时操作员是!

标签: c# expression


【解决方案1】:

What does Expression.Quote() do that Expression.Constant() can’t already do? 解释了Quote 的作用。

现在的问题是 LINQ 提供程序在实际场景中何时会遇到 Quote 操作。当您调用将表达式树作为参数的IQueryable 操作时,它会出现。例如,bool Queryable.Where(IQueryable inputQuery, Expression<Func<..., bool>> predicate) 采用表达式树。

如果您说myQueryable.Where(x => ...),C# 编译器将生成Expression.* 调用来构建该表达式树并将其传递给Where。没有Quote 这里。

但如果表达式树的生成是嵌套,则使用Quote

myQueryable.Where(x => x.SomeCollection.Any(y => ...))

这里,y => ... 部分的类型为 Expression<..., bool>。这需要Quote

我相信一个简单的 LINQ 提供程序可以解开/丢弃 Quote 并生成代码,就好像它不存在一样。如果您想完全正确,则需要在 LINQ 提供程序中对这种情况进行特殊处理。问题中的 LINQ 提供程序代码是“演示代码”质量,因此它不会这样做。

您可以使用https://sharplab.io/ 来处理不同类型的查询,以查看编译器生成的内容。例如。

using System;
using System.Linq;

public class C {
    public void M2() {
        var query =
            new SomeClass[0]
            .AsQueryable()
            .Where(x => x.SomeCollection.Any(y => y % 2 == 0));
    }
    static bool F(System.Linq.Expressions.Expression<Func<int, bool>> e) { return true; }

    class SomeClass {
        public IQueryable<int> SomeCollection { get; set; }
    }
}

https://sharplab.io/#v2:CYLg1APgAgDABFAjAbgLAChYMQOgDICWAdgI5roZQDMCATHAMJwDeGc7CNUALHALK0AFAEoWbDhIBuAQwBOcEgFcAprICecALziJuuEWUB3OAGUA9gFtlDADbSAzvYDaMALo69HHAEF7ARRV1aQAjG2URD084HAB1AAtVcIAPLQA+OCSccysGMxswgGMAFwIzIh8iNUENTXSNAFI4ek1NOBhhYXIJAF8PJAA2OGCzPLgAMUEkfGISHABRJIAHWWVHUqJ7eaWVtbKAHigAVj3iIoAaIZGbVPTlUWYEAHY4ItkVZDhe9Ak++mzrOyOMTfTzUOAASQCqjUITCJyIRXS/1y+WUxXWLDgAHNlEUPvZcR8vj0MF8gA

【讨论】:

    猜你喜欢
    • 2013-12-18
    • 1970-01-01
    • 2018-09-28
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 2021-08-04
    相关资源
    最近更新 更多