2

我正在尝试关注这一系列文章。我在第 2 部分和第 3 部分之间,但遇到了一些问题。

我正在 VB.Net 中编写代码,这引发了一些怪癖。

具体来说,在访问表达式树时,字符串比较没有按预期工作。

QueryProvider 中的这个方法(第 2 部分

Protected Overrides Function VisitMethodCall(m As MethodCallExpression) As Expression
    If m.Method.DeclaringType = GetType(Queryable) AndAlso m.Method.Name = "Where" Then
        sb.Append("SELECT * FROM (")
        Me.Visit(m.Arguments(0))
        sb.Append(") AS T WHERE ")
        Dim lambda As LambdaExpression = DirectCast(StripQuotes(m.Arguments(1)), LambdaExpression)
        Me.Visit(lambda.Body)
        Return m
    End If
    Throw New NotSupportedException(String.Format("The method '{0}' is not supported", m.Method.Name))
End Function

为字符串比较抛出 NotImplementedException

m.Method.DeclaringType是 类型Microsoft.VisualBasic.CompilerServices.Operators并且 m.Method.NameCompareString。看起来 VB 对字符串相等的处理方式略有不同,并且没有以正确的方式进行处理。

我正在使用 aQuery.Where(function(x) x.Content_Type <> "")进行测试。

VisitBinary(b As BinaryExpression)具体来说,如果我调试对(也是第 2 部分)的调用,b{(CompareString(x.Content_Type, "", False) != 0)}

然后,它会尝试访问b.Left( CompareString(x.Content_Type, "", False)),这是我们从 . 中的洞落入的地方VisitMethodCall

如果我只是将 VisitMethodCall 中的 If 展开为

    If (
            m.Method.DeclaringType = GetType(Queryable) AndAlso
            m.Method.Name = "Where"
        ) Or (
            m.Method.DeclaringType = GetType(Microsoft.VisualBasic.CompilerServices.Operators) AndAlso
            m.Method.Name = "CompareString") Then

它在尝试将其转换为时抛出 InvalidCastException StripQuotes(m.Arguments(1))LambdaExpression说它是 a ConstantExpression

我需要做什么才能从 VB 中正确处理字符串比较?

4

1 回答 1

2

使用以下类:

Imports System.Linq.Expressions

Public Class VbCompareReplacer
    Inherits ExpressionVisitor

    Public Overrides Function Visit(node As Expression) As Expression
        If Not TypeOf node Is BinaryExpression Then Return MyBase.Visit(node)

        Dim binaryExpression = DirectCast(node, BinaryExpression)

        If Not TypeOf binaryExpression.Left Is MethodCallExpression Then Return MyBase.Visit(node)

        Dim method = DirectCast(binaryExpression.Left, MethodCallExpression)

        If Not (method.Method.DeclaringType = GetType(Microsoft.VisualBasic.CompilerServices.Operators) AndAlso
            method.Method.Name = "CompareString") Then Return MyBase.Visit(node)

        Dim left = method.Arguments(0)
        Dim right = method.Arguments(1)

        Return If(binaryExpression.NodeType = ExpressionType.Equal,
                  Expression.Equal(left, right),
                  Expression.NotEqual(left, right))
    End Function
End Class

现在,如果您有来自 vb 编译器的表达式,例如

Dim expressionFromVb As Expression(Of Func(Of String, Boolean)) = Function(x) x = "b"

它具有结构 {(CompareString(x, "b", False) == 0)} 使用

Dim newExpression = New VbCompareReplacer().Visit(expressionFromVb)

而不是expressionFromVb具有结构 {x => (x == "b")}。所有凌乱的 vb 比较都被预期的(不)等式比较所取代。如果您放入newExpression为 c# 编写的 linq 提供程序,它现在应该可以正常工作。

于 2012-10-02T21:44:09.653 回答