代码之家  ›  专栏  ›  技术社区  ›  TheSoftwareJedi jac

是否有一种简单的方法来附加lambda并重用lambda名称,以创建我的Linq where条件?

  •  4
  • TheSoftwareJedi jac  · 技术社区  · 16 年前

    我有一个用户控件,它接受一个Func,然后将其传递给IQuery的Linq“Where”扩展方法。这个想法是,从调用代码中,我可以传入所需的搜索函数。

    Func<Order, bool> func == a => true;
    if (txtName.Text.Length > 0) {
      //add it to the function
      func = a => func(a) && a.Name.StartsWith(txtName.Text);
    }
    if (txtType.Text.Length > 0) {
      //add it to the function
      func = a => func(a) && a.Type == txtType.Text;
    }
    ..... etc .....
    

    5 回复  |  直到 16 年前
        1
  •  6
  •   Dario    16 年前

    只需将当前lambda保存在临时变量中以防止递归。

    var tempFunc = func;
    func = a => tempFunc(a) && ...
    
        2
  •  1
  •   Marc Gravell    16 年前

    如果你想做一个“and”组合,首选是使用多个“where”子句:

    IQueryable<Order> query = ...
    if (!string.IsNullOrEmpty(txtName.Text.Length)) {
      //add it to the function
      query = query.Where(a => a.Name.StartsWith(txtName.Text));
    }
    if (!string.IsNullOrEmpty(txtType.Text.Length)) {
      //add it to the function
      query = query.Where(a => a.Type == txtType.Text);
    }
    

    您可以使用表达式构建(AndAlso、Invoke等)执行更复杂的操作,但对于“and”组合来说,这不是必需的。

    static Expression<Func<T, bool>> OrElse<T>(
        this Expression<Func<T, bool>> lhs,
        Expression<Func<T, bool>> rhs)
    {
        var row = Expression.Parameter(typeof(T), "row");
        var body = Expression.OrElse(
            Expression.Invoke(lhs, row),
            Expression.Invoke(rhs, row));
        return Expression.Lambda<Func<T, bool>>(body, row);
    }
    static Expression<Func<T, bool>> AndAlso<T>(
        this Expression<Func<T, bool>> lhs,
        Expression<Func<T, bool>> rhs)
    {
        var row = Expression.Parameter(typeof(T), "row");
        var body = Expression.AndAlso(
            Expression.Invoke(lhs, row),
            Expression.Invoke(rhs, row));
        return Expression.Lambda<Func<T, bool>>(body, row);
    }
    

    容易的。因此,为什么通常最好使用 Queryable.Where Queryable.Concat

        3
  •  0
  •   bytebender    16 年前

    我正在做这件事。..我使用表达式是因为Func是编译代码,其中 Expression<Func<YourObect, boo>>

    在您的搜索页面上,您将实现如下代码:

    SearchCritera<Customer> crit = new SearchCriteria<Customer>();
    
    if (txtName.Text.Length > 0) {
      //add it to the function
      crit.Add(a.Name.StartsWith(txtName.Text));
    }
    
    if (txtType.Text.Length > 0) {
      //add it to the function
      crit.Add(a.Type == txtType.Text));
    }
    

    SearchCriteria对象看起来像这样。..

    public class SearchCritera<TEntity>
        {
            private List<Expression<Func<TEntity, bool>>> _Criteria = new List<Expression<Func<TEntity, bool>>>();
    
            public void Add(Expression<Func<TEntity, bool>> predicate)
            {
                _Criteria.Add(predicate);
            }
    
            // This is where your list of Expression get built into a single Expression 
            // to use in your Where clause
            public Expression<Func<TEntity, bool>> BuildWhereExpression()
            {
                Expression<Func<TEntity, bool>> result = default(Expression<Func<TEntity, bool>>);
                ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "entity");
                Expression previous = _Criteria[0];
    
                for (int i = 1; i < _Criteria.Count; i++)
                {
                    previous = Expression.And(previous, _Criteria[i]);
                }
    
                result = Expression.Lambda<Func<TEntity, bool>>(previous, parameter);
    
                return result;
            }
        }
    

    public List<Customer> FindAllCustomers(SearchCriteria criteria)
    {
       return LinqToSqlDataContext.Customers.Where(SearchCriteria.BuildWhereExpression()).ToList();
    }
    

    这是我第一次把它编码出来,你可能需要为你的目的做一些更改,我知道这很复杂,但当我真正去做的时候,我会对它进行单元测试,但这是我一直在脑海中徘徊的想法。..

        4
  •  0
  •   TheSoftwareJedi jac    16 年前

    PredicateBuilder !!!

    此扩展方法将防止递归:

        public static Func<T, bool> And<T>(this Func<T, bool> f1, Func<T, bool> f2)
        {
            return a => f1(a) && f2(a);
        }
    
        public static Func<T, bool> Or<T>(this Func<T, bool> f1, Func<T, bool> f2)
        {
            return a => f1(a) || f2(a);
        }
    

    Func<Order, bool> func == a => true;
    if (txtName.Text.Length > 0) {
      //add it to the function
      func.And(a => a.Name.StartsWith(txtName.Text));
    }
    if (txtType.Text.Length > 0) {
      //add it to the function
      func.And(a => a.Type == txtType.Text);
    }
    
        5
  •  0
  •   Amy B    16 年前
    Dictionary<Func<bool>, Expression<Func<Order, bool>>> filters =
      new Dictionary<Func<bool>, Expression<Func<Order, bool>>>();
    // add a name filter
    filters.Add(
      () => txtName.Text.Length > 0,
      a => a.Name.StartsWith(txtName.Text)
    );
    // add a type filter
    filters.Add(
      () => txtType.Text.Length > 0,
      a => a.Type == txtType.Text
    );
    

    var query = dc.Orders.AsQueryable();
    
    foreach( var filter in filters
      .Where(kvp => kvp.Key())
      .Select(kvp => kvp.Value) )
    {
      var inScopeFilter = filter;
      query = query.Where(inScopeFilter);
    }