Last active
October 4, 2019 00:02
-
-
Save mcintyre321/6294588 to your computer and use it in GitHub Desktop.
Replacing a case-sensitive methods in an Expression Tree with a case-insensitive equivalents using QueryInterceptor. Very cool! This is runnable in LinqPad if you add the QueryInterceptor Nuget package
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
var words = new []{"HELLO"}.AsQueryable().SetComparer(StringComparison.CurrentCultureIgnoreCase); | |
words.Where (x => x.StartsWith("hel")).Dump(); | |
words.Where (x => x.Contains("ell")).Dump(); | |
words.Where (x => x.EndsWith("llo")).Dump(); | |
words.Where (x => x.Equals("hello")).Dump(); | |
words.Where (x => x == "hello").Dump(); | |
words.Where (x => x != "hello").Dump(); //dont want to match this one... | |
} | |
public static class IQueryableCaseExtensions | |
{ | |
public static IQueryable<T> SetComparer<T>(this IQueryable<T> q, StringComparison sc){ | |
return q | |
.InterceptWith(new SetComparerExpressionVisitor(sc)); | |
} | |
} | |
public class SetComparerExpressionVisitor : ExpressionVisitor | |
{ | |
readonly StringComparison _comparer; | |
public SetComparerExpressionVisitor(StringComparison comparer) | |
{ | |
_comparer = comparer; | |
} | |
protected override Expression VisitBinary(BinaryExpression node) | |
{ | |
if (node.Left.Type == typeof (string) && node.Right.Type == typeof (string)) | |
{ | |
if (node.NodeType == ExpressionType.Equal) | |
{ | |
var exp = ((LambdaExpression) MakeExpression(s => s.Equals("asdf", _comparer))).Body; | |
exp = new ReplacingVisitor(((dynamic) exp).Arguments[0], ((dynamic) node).Left).Visit(exp); | |
exp = new ReplacingVisitor(((dynamic) exp).Object, ((dynamic) node).Right).Visit(exp); | |
return exp; | |
} | |
if (node.NodeType == ExpressionType.NotEqual) | |
{ | |
var exp = ((LambdaExpression) MakeExpression(s => !s.Equals("asdf", _comparer))).Body; | |
exp = new ReplacingVisitor(((dynamic) exp).Operand.Arguments[0], ((dynamic) node).Left).Visit(exp); | |
exp = new ReplacingVisitor(((dynamic) exp).Operand.Object, ((dynamic) node).Right).Visit(exp); | |
return exp; | |
} | |
} | |
return base.VisitBinary(node); | |
} | |
protected override Expression VisitMethodCall(MethodCallExpression node) | |
{ | |
if (node.Method.DeclaringType == typeof (string)) | |
{ | |
if (node.Method.Name == "Contains") | |
{ | |
var exp = ((LambdaExpression) MakeExpression(s => s.IndexOf("asdf", _comparer) > -1)).Body; | |
exp = | |
new ReplacingVisitor(((dynamic) exp).Left.Arguments[0], ((dynamic) node).Arguments[0]).Visit(exp); | |
exp = new ReplacingVisitor(((dynamic) exp).Left.Object, ((dynamic) node).Object).Visit(exp); | |
return exp; | |
} | |
if (node.Method.Name == "StartsWith") | |
{ | |
var exp = ((LambdaExpression) MakeExpression(s => s.IndexOf("asdf", _comparer) == 0)).Body; | |
exp = | |
new ReplacingVisitor(((dynamic) exp).Left.Arguments[0], ((dynamic) node).Arguments[0]).Visit(exp); | |
exp = new ReplacingVisitor(((dynamic) exp).Left.Object, ((dynamic) node).Object).Visit(exp); | |
return exp; | |
} | |
if (node.Method.Name == "EndsWith") | |
{ | |
var exp = ((LambdaExpression) MakeExpression(s => s.EndsWith("asdf", _comparer))).Body; | |
exp = new ReplacingVisitor(((dynamic) exp).Arguments[0], ((dynamic) node).Arguments[0]).Visit(exp); | |
exp = new ReplacingVisitor(((dynamic) exp).Object, ((dynamic) node).Object).Visit(exp); | |
return exp; | |
} | |
if (node.Method.Name == "Equals") | |
{ | |
var exp = ((LambdaExpression) MakeExpression(s => s.Equals("asdf", _comparer))).Body; | |
exp = new ReplacingVisitor(((dynamic) exp).Arguments[0], ((dynamic) node).Arguments[0]).Visit(exp); | |
exp = new ReplacingVisitor(((dynamic) exp).Object, ((dynamic) node).Object).Visit(exp); | |
return exp; | |
} | |
} | |
return base.VisitMethodCall(node); | |
} | |
public Expression MakeExpression(Expression<Func<string, bool>> exp) | |
{ | |
return exp; | |
} | |
} | |
public class ReplacingVisitor : ExpressionVisitor { | |
Func<Expression, bool> match; | |
Func<Expression, Expression> createReplacement; | |
public ReplacingVisitor(Expression from, Expression to){ | |
match = node => from == node; | |
createReplacement = node => to; | |
} | |
public override Expression Visit(Expression node){ | |
if (match(node)) return createReplacement(node); | |
return base.Visit(node); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I guess the string "asdf" is just a dummy string and can be anything?