在VB中的自定义Linq Provider中实现字符串比较器

时间:2012-08-30 10:30:34

标签: .net vb.net linq provider

我正在尝试关注this series of articles。我在第2和第3部分之间,但我遇到了一些问题。

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

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

QueryProvider中的此方法(Part 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.Operatorsm.Method.NameCompareString。看起来VB的字符串相等处理方式略有不同,并且没有以正确的方式获取。

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

具体来说,如果我调用VisitBinary(b As BinaryExpression)(同时Part 2)的调用,b{(CompareString(x.Content_Type, "", False) != 0)}

然后尝试访问b.LeftCompareString(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

在尝试将StripQuotes(m.Arguments(1))转换为LambdaExpression时会抛出InvalidCastException(表示它是ConstantExpression

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

1 个答案:

答案 0 :(得分: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,&#34; b&#34;,False)== 0)}使用

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

而不是expressionFromVb,其结构为{x =&gt; (x ==&#34; b&#34;)}。所有混乱的vb比较都被预期的(in-)相等比较所取代。如果将newExpression放入为c#编写的linq提供程序中,它现在应该可以正常工作。