2012-08-30 53 views
2

我试图关注this series of articles。我介于第2部分和第3部分之间,但有一些问题。在VB自定义Linq Provider中实现字符串比较器

我在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 

是投掷为字符串比较

m.Method.DeclaringType一个NotImplementedException是Microsoft.VisualBasic.CompilerServices.Operators类型的,并且是m.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 (
      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正确处理字符串比较?

+0

@DanielHilgarth tbh我[不相信你是正确的](http://stackoverflow.com/questions/208381/whats-the-difference-between-anonymous-methods-c-2-0-and- lambda表达式)(lambas可以用来代替anon funcs/delegates,但不一定是),但是无论哪种方式,QueryProvider应该能够遍历表达式树,该表达式树可以很好地包含lambda表达式并将其转换转换为查询字符串以在别处使用。 – Basic

回答

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”,假)== 0)}使用

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

代替expressionFromVb具有以下结构的{X =>(X == “b”)}。所有凌乱的vb比较被预期的(in)相等比较所取代。如果您将newExpression放入您为c#编写的linq提供程序中,它现在应该可以正常工作。

+2

+1这是一个非常优雅的解决方案。当我明天在工作时,我会给它一个旋转,看看它是怎么回事,谢谢。 – Basic