强制VB.NET生成和C#一样的字符串比较表达式?
Force VB.NET to generate the same string comparison expression as C#?
这里有点类似的问题:
Difference between C# and VB.Net string comparison
...但和我现在问的不一样
我正在创建一个简单的表达式 walker,它将 lambda 转换为 SQL WHERE 子句。我这样称呼它:
GetEntities<MyEntity>(e => e.MyProperty == MyValue)
C# 按照我的预期创建表达式,它是一个 BinaryExpression
,由左侧的 MemberExpression
和右侧的 ConstantExpression
组成,如下所示:
$e.MyProperty == MyValue
然而,VB.NET 调用 CompareString
,它将 MyProperty
和 MyValue
作为参数传递给它,然后检查 return 结果是否为 0。当这样调用时:
GetEntities(Of MyEntity)(Function(e) e.MyProperty = MyValue)
...它生成如下表达式:
.Call Microsoft.VisualBasic.CompilerServices.Operators.CompareString(
$e.MyProperty, MyValue, False) == 0
这显然不能很好地与我的表达式 walker 一起玩,所以我现在必须遍历方法表达式以获取传递给它的值等等。
有没有办法在所有情况下强制VB.NET生成与C#相同的表达式树?我不愿意编写大量代码来解释这些显着差异。
正如我在评论中指出的那样,存在差异是有原因的。 Vb.Net 运算符的工作方式与 C# 中的不同。
所以您的问题的答案是否定的,您无法更改 Vb.Net 的运算符使其像 C# 一样工作。
您可以做的是创建一个从 Vb 表达式树到 C# 表达式树的转换:
internal sealed class VbComparisonTransform : ExpressionVisitor
{
protected override Expression VisitBinary(BinaryExpression node) {
if (node == null)
throw new ArgumentNullException("node");
if (node.Left.NodeType != ExpressionType.Call)
return base.VisitBinary(node);
var callNode = node.Left as MethodCallExpression;
if (callNode.Method.DeclaringType.FullName != "Microsoft.VisualBasic.CompilerServices.Operators")
return base.VisitBinary(node);
if (callNode.Method.Name != "CompareString")
return base.VisitBinary(node);
switch (node.NodeType) {
case ExpressionType.LessThan:
return Expression.LessThan(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.LessThanOrEqual:
return Expression.LessThanOrEqual(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.Equal:
return Expression.Equal(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.NotEqual:
return Expression.NotEqual(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.GreaterThan:
return Expression.GreaterThan(callNode.Arguments[0], callNode.Arguments[1]);
default:
string throwmessage = string.Format(CultureInfo.InvariantCulture, "VB.Net compare expression of type {0} not supported", node.NodeType);
throw new NotSupportedException(throwmessage);
}
}
}
然后像这样使用它:
public Expression ToCSharpComparisons(Expression expression) {
if (expression == null)
throw new ArgumentNullException("expression");
return new VbComparisonTransform().Visit(expression);
}
这里有点类似的问题:
Difference between C# and VB.Net string comparison
...但和我现在问的不一样
我正在创建一个简单的表达式 walker,它将 lambda 转换为 SQL WHERE 子句。我这样称呼它:
GetEntities<MyEntity>(e => e.MyProperty == MyValue)
C# 按照我的预期创建表达式,它是一个 BinaryExpression
,由左侧的 MemberExpression
和右侧的 ConstantExpression
组成,如下所示:
$e.MyProperty == MyValue
然而,VB.NET 调用 CompareString
,它将 MyProperty
和 MyValue
作为参数传递给它,然后检查 return 结果是否为 0。当这样调用时:
GetEntities(Of MyEntity)(Function(e) e.MyProperty = MyValue)
...它生成如下表达式:
.Call Microsoft.VisualBasic.CompilerServices.Operators.CompareString(
$e.MyProperty, MyValue, False) == 0
这显然不能很好地与我的表达式 walker 一起玩,所以我现在必须遍历方法表达式以获取传递给它的值等等。
有没有办法在所有情况下强制VB.NET生成与C#相同的表达式树?我不愿意编写大量代码来解释这些显着差异。
正如我在评论中指出的那样,存在差异是有原因的。 Vb.Net 运算符的工作方式与 C# 中的不同。
所以您的问题的答案是否定的,您无法更改 Vb.Net 的运算符使其像 C# 一样工作。
您可以做的是创建一个从 Vb 表达式树到 C# 表达式树的转换:
internal sealed class VbComparisonTransform : ExpressionVisitor
{
protected override Expression VisitBinary(BinaryExpression node) {
if (node == null)
throw new ArgumentNullException("node");
if (node.Left.NodeType != ExpressionType.Call)
return base.VisitBinary(node);
var callNode = node.Left as MethodCallExpression;
if (callNode.Method.DeclaringType.FullName != "Microsoft.VisualBasic.CompilerServices.Operators")
return base.VisitBinary(node);
if (callNode.Method.Name != "CompareString")
return base.VisitBinary(node);
switch (node.NodeType) {
case ExpressionType.LessThan:
return Expression.LessThan(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.LessThanOrEqual:
return Expression.LessThanOrEqual(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.Equal:
return Expression.Equal(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.NotEqual:
return Expression.NotEqual(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(callNode.Arguments[0], callNode.Arguments[1]);
case ExpressionType.GreaterThan:
return Expression.GreaterThan(callNode.Arguments[0], callNode.Arguments[1]);
default:
string throwmessage = string.Format(CultureInfo.InvariantCulture, "VB.Net compare expression of type {0} not supported", node.NodeType);
throw new NotSupportedException(throwmessage);
}
}
}
然后像这样使用它:
public Expression ToCSharpComparisons(Expression expression) {
if (expression == null)
throw new ArgumentNullException("expression");
return new VbComparisonTransform().Visit(expression);
}