我开始使用 Jon Koeter 从博客文章中发布的代码在另一个似乎不再存在的答案中。
但是,我发现它并不能正常工作,尤其是在使用IEnumerable 时。也就是说,它使用ToArray 解析可枚举并使用正则表达式进行匹配,而不是内置函数。
由于我只想在完成过滤后解析我的IEnumerable,因此我进行了一些更改以转换为IQueryable,然后使用其余代码找到正确的实体框架方法并调用它。这样,查询本身直到稍后才会针对数据库调用,并且避免了使用正则表达式。
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, Expression<Func<T, string>> valueSelector, string value, char wildcard)
{
return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
}
public static IEnumerable<T> WhereLike<T>(this IEnumerable<T> source, Expression<Func<T, string>> valueSelector, string value, char wildcard)
{
return source.AsQueryable().WhereLike(valueSelector, value, wildcard);
}
private static Expression<Func<T, bool>> BuildLikeExpression<T>(Expression<Func<T, string>> valueSelector, string value, char wildcard)
{
if (valueSelector == null) throw new ArgumentNullException("valueSelector");
var method = GetLikeMethod(value, wildcard);
value = value.Trim(wildcard);
var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value));
var parameter = valueSelector.Parameters.Single();
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
private static MethodInfo GetLikeMethod(string value, char wildcard)
{
var methodName = "Equals";
var textLength = value.Length;
value = value.TrimEnd(wildcard);
if (textLength > value.Length)
{
methodName = "StartsWith";
textLength = value.Length;
}
value = value.TrimStart(wildcard);
if (textLength > value.Length)
{
methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith";
}
var stringType = typeof(string);
return stringType.GetMethod(methodName, new[] { stringType });
}
用法:
// example data set
var data = new List<Person> {
new Person{FirstName="John", LastName="Smith"},
new Person{FirstName="Jane", LastName="Doe"}
};
data.WhereLike(x=>x.FirstName, "John", "%"); // returns John Smith
data.WhereLike(x=>x.FirstName, "J%", "%"); // returns John Smith and Jane Smith