c# - LINQ 表达式添加不必要的括号

标签 c# .net expression linq-expressions

我正在用 C# 构建 LINQ 表达式,如下所示:

public static Expression BuildEqualsExpression(
    ParameterExpression Parameter,
    PropertyInfo Property,
    ConstantExpression constant)
{
    Expression propertyExpression = Expression.Property(Parameter, Property);
    return Expression.Equal(propertyExpression, constant);
}

返回的表达式是

(r.Property == constant)

当我想要的是

r.Property == constant

没有括号。我的 IQueryProvider 没有平等对待这两个语句。有谁知道如何去掉括号?

如果我AND将其中两个放在一起,我得到

((r.Property1 == constant) And (r.Property2 == constant))

当我想要的时候

r.Property1 == constant And r.Property2 == constant

因为它们不是等价谓词。

编辑:

感谢您的帮助。事实证明,在 SQL Server 2014 中,使用此命令:

OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY 

当实际行数<100时,这会导致查询执行的非常慢。

最佳答案

没有显式表示括号的 LINQ 表达式节点。相反,运算符优先级和结合性是从表达式树的结构中自动推断出来的。

您或查询提供者似乎正在对表达式调用 ToString()。 不要这样做。 expression trees specification状态:

Expression.ToString is for light weight debugging purposes only. [...]

ToString does not try to return semantically accurate C# or VB code in particular. We try to return terse strings loosely suggesting what an ET [expression tree] node contains for quick inspection only.

正如 Thomas Levesque 在评论中指出的那样,最好的方法是让查询提供程序直接使用表达式树而不是字符串。

如果查询提供程序只接受字符串,那么您必须自己将表达式转换为字符串。额外的括号是有问题的,你的任务将变得复杂,因为你仍然需要插入括号来区分,比方说,(1 + 2) * 3 和 1 + (2 * 3)。

这里有一些代码可以帮助您入门:

private static readonly Dictionary<ExpressionType, string> s_binaryOperators =
    new Dictionary<ExpressionType, string>
    {
        { ExpressionType.Equal, " == " },
        { ExpressionType.And, " AND " },
    };

public static void ToString(Expression expression, StringBuilder builder)
{
    switch (expression.NodeType)
    {
        case ExpressionType.Parameter:
            builder.Append(((ParameterExpression)expression).Name);
            break;

        case ExpressionType.Constant:
            builder.Append(((ConstantExpression)expression).Value);
            break;

        case ExpressionType.MemberAccess:
            var memberExpression = (MemberExpression)expression;
            // TODO: Add parentheses if memberExpression.Expression.NodeType
            // has lower precedence than the current expression.
            ToString(memberExpression.Expression, builder);
            builder.Append('.').Append(memberExpression.Member.Name);
            break;

        case ExpressionType.Equal:
        case ExpressionType.And:
            var binaryExpression = (BinaryExpression)expression;
            // TODO: Add parentheses if binaryExpression.Left.NodeType
            // has lower precedence than the current expression.
            ToString(binaryExpression.Left, builder);
            builder.Append(s_binaryOperators[expression.NodeType]);
            // TODO: Add parentheses if binaryExpression.Right.NodeType
            // has lower precedence than the current expression.
            ToString(binaryExpression.Right, builder);
            break;

        default:
            throw new NotImplementedException();
    }
}

关于c# - LINQ 表达式添加不必要的括号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33584994/

相关文章:

c# - 使用 IronPython 和 .Net 的鼠标现状

c# - 命名空间 'Resources' 已经包含了 'SiteResources' 的定义

c# - 在运行时动态扩展类型?

c++ - if 语句表达式调用函数,需要测试是否为真

c# - 将 Lambda 表达式声明为类常量字段

c# - 我有一个正则表达式问题删除 & 字符

c# - ASP.Net MVC - "Cannot Create Instance of an Interface"

c# - 如何设计两个相似(但不完全)的类?

c# - String.Format double 没有分隔符

c - 声明是表达式吗?