技术开发 频道

VB 表达式树–字符串比较

【IT168 技术文档】

    对于那些想写LINQ provider的人来说,表达式树很有意思,它能对lambda表达式进行推理从而得到LINQ provider。一般来说,任何想了解lambda表达式的人应该对表达式树也感兴趣。

    今天,我打算专门为这些正在写代码实现表达式树的人写点东西。即便你现在没写这些代码,我仍然希望你能看下去,因为无论如何这些内容都是非常有趣的。

    在这篇博客里我将讨论一下字符串的比较以及他们在表达式树里的表现。Jonathan(我们的PM)和我曾经写过一个LINQ provider的例子,我们认为这段代码非常有用,现在把它共享出来。

    在VB里,通过对option compare的设置就可以用=操作符对区分大小写和不区分大小写的字符串进行比较。

    为了实现这些,VB编译器在运行时调用了Microsoft.VisualBasic.CompilerServices.Operators.CompareString,这个方法有三个参数:其中2个是操作数,1个是标志符指示比较类型。

    当VB编译器为字符串相等操作符生成表达式树的时候,我们通过构造表达式来调用CompareString方法以保证字符串的正确比较。这是因为在默认的情况下,表达式树中“等于”节点的API负责区分大小写。而且,“等于”节点在VB中并未考虑到特殊字符串及字面上的“Nothing”的比较。

    这就意味着如果你想通过VB编译器生成的表达式树来写一个visitor,你就一定会期望这些二元操作符如<, <=, =, >=, 以及 >,它们的左边为CompareString方法,右边为0。当你看到这些,你需要根据CompareString中第三个参数的使用方法来正确拆分它里面的参数。

    但是,如果你的provider不进行字符串比较的话(比如LINQ to SQL),那么你只要用下面的代码,把方法调用中的二元运算符转换为方法调用参数中的二元运算符。

    然后在你的visitor里调用这个方法进行转换,接着通过方法返回的节点运行visitor,将字符串比较作为二元操作符处理。不过这种方法无法区分大小写。

Friend Shared Function ConvertVBStringCompare(ByVal exp As BinaryExpression) As BinaryExpression If exp.Left.NodeType = ExpressionType.Call Then Dim compareStringCall = CType(exp.Left, MethodCallExpression) If compareStringCall.Method.DeclaringType.FullName = "Microsoft.VisualBasic.CompilerServices.Operators" _ AndAlso compareStringCall.Method.Name = "CompareString" Then Dim arg1 = compareStringCall.Arguments(0) Dim arg2 = compareStringCall.Arguments(1) Select Case exp.NodeType Case ExpressionType.LessThan Return Expression.LessThan(arg1, arg2) Case ExpressionType.LessThanOrEqual Return Expression.GreaterThan(arg1, arg2) Case ExpressionType.GreaterThan Return Expression.GreaterThan(arg1, arg2) Case ExpressionType.GreaterThanOrEqual Return Expression.GreaterThanOrEqual(arg1, arg2) Case Else Return Expression.Equal(arg1, arg2) End Select End If End If Return exp End Function

    下面这个例子并未做任何有用的事情,但你可以从中了解到如何使用上面定义的方法。

Sub VisitBinary(ByVal exp As BinaryExpression) exp = ConvertVBStringCompare(exp) Visit(exp.Left) Visit(exp.Right) End Sub

 

0
相关文章