强制VB.NET生成与C#相同的字符串比较表达式?

3

这里有一个类似的问题:

C#和VB.Net字符串比较的区别

...但这不是我现在要问的。

我正在创建一个简单的表达式解析器,将lambda表达式转换为SQL WHERE子句。 我像这样调用它:

GetEntities<MyEntity>(e => e.MyProperty == MyValue)

C#会根据我的预期创建表达式,其中表达式是一个BinaryExpression,其左侧是一个MemberExpression,右侧是一个ConstantExpression,如下所示:

$e.MyProperty == MyValue

然而,VB.NET 调用 CompareString,并将 MyPropertyMyValue 作为参数传递,并检查返回结果是否为 0。当以这种方式调用时:

GetEntities(Of MyEntity)(Function(e) e.MyProperty = MyValue)

...它会生成如下表达式:

.Call Microsoft.VisualBasic.CompilerServices.Operators.CompareString(
    $e.MyProperty, MyValue, False) == 0

显然,这与我的表达式解析器不太兼容,因此我现在必须遍历方法表达式以获取传递给它的值等等。

是否有一种方法可以强制 VB.NET 以 所有情况 生成与 C# 相同的表达式树?我不想写大量代码来处理这些重大差异。


你能否展示你的VB代码以便完整吗? - Matt Wilko
3
它创建不同的树的原因是在VB中的=与C#中的==不同(如空值处理和大小写敏感性)。您是否希望您的walker在VB中使用C#行为?这会不会使VB用户困惑? - adrianm
@adrianm 有人会感到困惑吗?在相等性检查的上下文中,a == ba = b 的语义是相同的。所有这些表达式的工作都是在幕后完成的,因此开发人员只需要明白他们正在进行相等性检查。 - oscilatingcretin
1
@oscilatingcretin 但语义并不相同。你只是不在意这些差异。这并不意味着它们不存在。 - Servy
@oscilatingcretin 相关差异已经在此处提到 - Servy
显示剩余4条评论
1个回答

2

正如我在评论中提到的那样,这种差异是有原因的。Vb.Net运算符的工作方式与C#不同。

所以你的问题的答案是否定的,你不能改变Vb.Net的运算符使其像C#一样工作。

你可以做的是创建一个从Vb表达式树到C#表达式树的转换:

    internal sealed class VbComparisonTransform : ExpressionVisitor
    {
        protected override Expression VisitBinary(BinaryExpression node) {
            if (node == null)
                throw new ArgumentNullException("node");

            if (node.Left.NodeType != ExpressionType.Call)
                return base.VisitBinary(node);

            var callNode = node.Left as MethodCallExpression;
            if (callNode.Method.DeclaringType.FullName != "Microsoft.VisualBasic.CompilerServices.Operators")
                return base.VisitBinary(node);
            if (callNode.Method.Name != "CompareString")
                return base.VisitBinary(node);

            switch (node.NodeType) {
                case ExpressionType.LessThan:
                    return Expression.LessThan(callNode.Arguments[0], callNode.Arguments[1]);
                case ExpressionType.LessThanOrEqual:
                    return Expression.LessThanOrEqual(callNode.Arguments[0], callNode.Arguments[1]);
                case ExpressionType.Equal:
                    return Expression.Equal(callNode.Arguments[0], callNode.Arguments[1]);
                case ExpressionType.NotEqual:
                    return Expression.NotEqual(callNode.Arguments[0], callNode.Arguments[1]);
                case ExpressionType.GreaterThanOrEqual:
                    return Expression.GreaterThanOrEqual(callNode.Arguments[0], callNode.Arguments[1]);
                case ExpressionType.GreaterThan:
                    return Expression.GreaterThan(callNode.Arguments[0], callNode.Arguments[1]);
                default:
                    string throwmessage = string.Format(CultureInfo.InvariantCulture, "VB.Net compare expression of type {0} not supported", node.NodeType);
                    throw new NotSupportedException(throwmessage);
            }
        }
    }

然后像这样使用它:

public Expression ToCSharpComparisons(Expression expression) {
    if (expression == null)
        throw new ArgumentNullException("expression");

    return new VbComparisonTransform().Visit(expression);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接