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.Operatorsm.Method.NameございますCompareString。文字列の等価性は VB によって少し異なる方法で処理され、正しい方法で取得されていないようです。

を使っQuery.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) 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比較は、予想される(不)同等の比較に置き換えられます。c#用に記述されたlinqプロバイダーに入れるnewExpressionと、正しく機能するはずです。

于 2012-10-02T21:44:09.653 に答える