我如何重构此 Lambda 中的 "Property to Use" 以使其可重用?

How can I Refactor This To Pass in the "Property to Use" in this Lambda to Make This Method Reusable?

在我的网页中,有多个文本框供用户输入复杂的查询。一个复杂的查询可以包含以下任何 Parameters:

  1. XX* 匹配 XX
  2. 开头的所有内容
  3. *XX 所有 结尾为 XX
  4. *XX* 所有内容 包含 XX
  5. XX123-XX129 匹配从 XX123 到 XX129
  6. 包含范围
  7. XX444 精确的个人价值
  8. ...以上any/all的任何逗号分隔组合

实施这不是我的问题;我的问题是以 可重用 方式为多个值实现它。

下面的示例在 Item.Value 属性 上过滤 Items

public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
    IEnumerable<Parameter> itemValues)
{
    var parameters = (itemValues ?? Enumerable.Empty<Parameter>()).ToList();
    if (parameters.IsEmpty()) return items;

    var (wildCards, exactMatches) = parameters.SplitOnWildCards();

    var predicate = PredicateBuilder.New<Item>(); // https://github.com/scottksmith95/LINQKit

    wildCards.ForEach(wc =>
    {
        switch (wc)
        {
            case WildCardStartsWith startsWith:
                predicate = predicate.Or(s => s.Value.ToUpper().StartsWith(startsWith.ToString()));
                break;
            case WildCardContains contains:
                predicate = predicate.Or(s => s.Value.ToUpper().Contains(contains.ToString()));
                break;
            case WildCardEndsWith endsWith:
                predicate = predicate.Or(s => s.Value.ToUpper().EndsWith(endsWith.ToString()));
                break;
        }
    });

    if (exactMatches.Any())
        predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(s.Value.ToUpper()));

    return items.AsExpandableEFCore().Where(predicate);
}

我如何重构它以便我可以 "pass in" 将 Item.Value 传递给该方法,这样我也可以传入 Item.PartNumberItem.Foo 而不必复制所有我要过滤的每个 属性 的代码?我不能只传入 Item.Value...那只是一个字符串,在 lambda 语句中不起作用。

编写您的方法以获取表示字段引用的 ExpressionLambda

public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
    IEnumerable<Parameter> itemValues,
    Expression<Func<Item,string>> field)

然后在需要引用字段的代码中,使用LINQKit的Invoke方法:

case WildCardStartsWith startsWith:
    predicate = predicate.Or(s => field.Invoke(s).ToUpper().StartsWith(startsWith.ToString()));

最后,使用 LINQKit 的 Expand 方法内联扩展 field 引用,或者像在数据源上那样使用 AsExpandable

if (exactMatches.Any())
    predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(field.Invoke(s).ToUpper()));

return items.AsExpandableEFCore().Where(predicate);