LINQ表达式中不区分大小写的字符串比较

我正在尝试编写一个ExpressionVisitor来包装我的LINQ到对象表达式,以自动使它们的字符串比较不区分大小写,就像它们在LINQ-to-entities中一样。

编辑:我确实想要使用ExpressionVisitor,而不是仅仅在创建它时为我的表达式应用一些自定义扩展或其他一些重要原因:传递给我的ExpressionVisitor的表达式是由ASP.Net Web API ODATA层生成的,所以我无法控制它是如何生成的(即我不能小写它正在搜索的字符串,除非在此ExpressionVisitor中)。

必须支持LINQ to Entities。 不只是扩展。

这是我到目前为止所拥有的。 它在字符串上查找对“Contains”的调用,然后在该表达式内的任何成员访问上调用ToLower。

但是,它不起作用。 如果我在更改后查看表达式,它看起来对我来说是正确的,所以我不确定我可能做错了什么。

public class CaseInsensitiveExpressionVisitor : ExpressionVisitor { protected override Expression VisitMember(MemberExpression node) { if (insideContains) { if (node.Type == typeof (String)) { var methodInfo = typeof (String).GetMethod("ToLower", new Type[] {}); var expression = Expression.Call(node, methodInfo); return expression; } } return base.VisitMember(node); } private Boolean insideContains = false; protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == "Contains") { if (insideContains) throw new NotSupportedException(); insideContains = true; var result = base.VisitMethodCall(node); insideContains = false; return result; } return base.VisitMethodCall(node); } 

如果我在VisitMember方法的“返回表达式”行上设置断点,然后在“节点”和“表达式”变量上执行“ToString”,则断点会被击中两次,这里的两组值是:

第一击:

 node.ToString() "$it.LastName" expression.ToString() "$it.LastName.ToLower()" 

第二击:

 node.ToString() "value(System.Web.Http.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty" expression.ToString() "value(System.Web.Http.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty.ToLower()" 

我不太了解表达式,以弄清楚我在这一点上做错了什么。 有任何想法吗?

我从你的代码中制作了一个示例应用程序,看起来很有效:

  public class Test { public string Name; } public class CaseInsensitiveExpressionVisitor : ExpressionVisitor { protected override Expression VisitMember(MemberExpression node) { if (insideContains) { if (node.Type == typeof (String)) { var methodInfo = typeof (String).GetMethod("ToLower", new Type[] {}); var expression = Expression.Call(node, methodInfo); return expression; } } return base.VisitMember(node); } private Boolean insideContains = false; protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == "Contains") { if (insideContains) throw new NotSupportedException(); insideContains = true; var result = base.VisitMethodCall(node); insideContains = false; return result; } return base.VisitMethodCall(node); } } class Program { static void Main(string[] args) { Expression > expr = (t) => t.Name.Contains("a"); var expr1 = (Expression>) new CaseInsensitiveExpressionVisitor().Visit(expr); var test = new[] {new Test {Name = "A"}}; var length = test.Where(expr1.Compile()).ToArray().Length; Debug.Assert(length == 1); Debug.Assert(test.Where(expr.Compile()).ToArray().Length == 0); } } 

你可以像这样创建一个extesion方法:

 public static class Extensions { public static bool InsensitiveEqual(this string val1, string val2) { return val1.Equals(val2, StringComparison.OrdinalIgnoreCase); } } 

然后你可以像这样打电话:

 string teste = "teste"; string teste2 = "TESTE"; bool NOTREAL = teste.Equals(teste2); //FALSE bool REAL = teste.InsensitiveEqual(teste2); //true