Dynamic Filtering

Continuing my previous posts on dynamic LINQ, now it's time for dynamic filtering. For now, I'll focus on string matching.

There are four standard operators for string matching, which both NHibernate, Entity Framework and LINQ to SQL recognize:

  • Equals
  • Contains
  • StartsWith
  • EndsWith

So, if we want to apply filtering by one of these operators on a string property, we can use this code:


public enum MatchType
{
	StartsWith = 0,

	EndsWith = 1,

	Contains = 2,

	Equals = 3
}

public static List<T> Filter<T>(IEnumerable<T> enumerable, String propertyName, String filter, MatchType matchType)
{
	return (Filter(enumerable, typeof(T), propertyName, filter, matchType) as List<T>);
}

public static IList Filter(IEnumerable enumerable, Type elementType, String propertyName, String filter, MatchType matchType)
{
	MethodInfo asQueryableMethod = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(m => (m.Name == "AsQueryable") && (m.ContainsGenericParameters == false)).Single();
	IQueryable query = (enumerable is IQueryable) ? (enumerable as IQueryable) : asQueryableMethod.Invoke(null, new Object [] { enumerable }) as IQueryable;
	MethodInfo whereMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "Where").ToArray() [ 0 ].MakeGenericMethod(elementType);

	MethodInfo matchMethod = typeof(String).GetMethod
	(
		(matchType == MatchType.StartsWith) ?
			"StartsWith" :
			(matchType == MatchType.EndsWith) ?
				"EndsWith" :
				(matchType == MatchType.Contains) ?
					"Contains" : 
						"Equals",
		new Type [] { typeof(String) }
	);

	PropertyInfo displayProperty = elementType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
	MemberExpression member = Expression.MakeMemberAccess(Expression.Parameter(elementType, "n"), displayProperty);
	MethodCallExpression call = Expression.Call(member, matchMethod, Expression.Constant(filter));
	LambdaExpression where = Expression.Lambda(call, member.Expression as ParameterExpression);

	query = whereMethod.Invoke(null, new Object [] { query, where }) as IQueryable;

	MethodInfo toListMethod = typeof(Enumerable).GetMethod("ToList", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(elementType);
	IList list = toListMethod.Invoke(null, new Object [] { query }) as IList;

	return (list);
}

var list = new [] { new { A = "aa" }, new { A = "aabb" }, new { A = "ccaa" }, new { A = "ddaadd" } };

var contains = Filter(list, "A", "aa", MatchType.Contains);
var endsWith = Filter(list, "A", "aa", MatchType.EndsWith);
var startsWith = Filter(list, "A", "aa", MatchType.StartsWith);
var equals = Filter(list, "A", "aa", MatchType.Equals);

Perhaps I'll write some more posts on this subject in the near future.

Bookmark and Share

                             

3 Comments

Comments have been disabled for this content.