LINQ表达式添加了不必要的括号

时间:2015-11-07 16:27:26

标签: 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,这将导致查询执行速度非常慢。

1 个答案:

答案 0 :(得分:4)

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

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

  

Expression.ToString仅用于轻量级调试。 [...]

     

ToString不会尝试特别返回语义上准确的C#或VB代码。我们尝试返回简洁的字符串,松散地建议ET [表达式树]节点包含什么,以便仅进行快速检查。

正如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();
    }
}