【发布时间】:2013-03-21 21:25:22
【问题描述】:
我为 IQueryable 创建了一个通用搜索扩展方法,使您能够搜索单个属性以查看其中是否包含搜索词。
http://jnye.co/Posts/6/c%23-generic-search-extension-method-for-iqueryable
我现在想让用户选择多个属性以在每个属性中进行搜索,匹配 any 属性是否包含文本。
代码:
用户输入以下代码来执行此搜索:
string searchTerm = "Essex";
context.Clubs.Search(searchTerm, club => club.Name, club => club.County)
//Note: If possible I would rather something closer to the following syntax...
context.Clubs.Search(club => new[]{ club.Name, club.County}, searchTerm);
// ... or, even better, something similar to this...
context.Clubs.Search(club => new { club.Name, club.County}, searchTerm);
这将返回名称中或县中带有“埃塞克斯”的任何高尔夫球杆。
public static IQueryable<TSource> Search<TSource>(this IQueryable<TSource> source, string searchTerm, params Expression<Func<TSource, string>>[] stringProperties)
{
if (String.IsNullOrEmpty(searchTerm))
{
return source;
}
// The lamda I would like to reproduce:
// source.Where(x => x.[property1].Contains(searchTerm)
// || x.[property2].Contains(searchTerm)
// || x.[property3].Contains(searchTerm)...)
//Create expression to represent x.[property1].Contains(searchTerm)
var searchTermExpression = Expression.Constant(searchTerm);
//Build parameters
var parameters = stringProperties.SelectMany(prop => prop.Parameters);
Expression orExpression = null;
//Build a contains expression for each property
foreach (var stringProperty in stringProperties)
{
var checkContainsExpression = Expression.Call(stringProperty.Body, typeof(string).GetMethod("Contains"), searchTermExpression);
if (orExpression == null)
{
orExpression = checkContainsExpression;
}
//Build or expression for each property
orExpression = Expression.OrElse(orExpression, checkContainsExpression);
}
var methodCallExpression = Expression.Call(typeof(Queryable),
"Where",
new Type[] { source.ElementType },
source.Expression,
Expression.Lambda<Func<TSource, bool>>(orExpression, parameters));
return source.Provider.CreateQuery<TSource>(methodCallExpression);
}
错误
如果我将提供的参数数量更改为 1:
Expression.Lambda<Func<TSource, bool>>(orExpression, parameters.First()));
我收到一个新错误:
更新
我写了a post on the work discussed in this question。 Check it out on GitHub 也是。
【问题讨论】:
-
要做到这一点,您将不必重新编写树,将“其他” lambda 中的参数替换为您想要用作主控的参数。 ExpressionVisitor 是执行此操作的工具 - SwapExpressionVisitor 非常容易编写(或使用此处的 stackoverflow.com/a/15293475/23354)
-
更改方法签名以便只传入一个 lambda 会更容易吗?即
.Search(club => new { club.Name, club.County}, searchTerm);还是坚持使用 params 实现? -
这应该不是问题。使用 ExpressionVisitor 实际上很容易 - 抱歉,我不在 IDE 中
-
我会坚持使用
params方式。然后,您将获得一组Expression实例,而不是一个Expression,其中包含您必须解析的数组。 -
@MarcGravell:好的,感谢 ExpressionVisitor 指针...我会检查一下
标签: c# generics lambda expression-trees