【问题标题】:Lambda Expressions and searchingLambda 表达式和搜索
【发布时间】:2011-03-27 17:02:27
【问题描述】:

假设我有一个具有以下内容的表单:

名称:文本框
电子邮件:文本框
年龄:文本框

现在我想根据这个过滤器文本框获取客户集合

所以我想使用类似的东西:

List<customer> customers = getCustomerswhere(c=>c.name == txtName.Text && Email == txtEmail.Text);

现在我当然不知道他会填什么,他不会填什么

if (txtName.Text.trim() != "")
   //something like c=>c.Name == txtName.text;
if (txtEmail.Text.trim() != "")
   //something like and c=>c.Email == txtEmail.text;

我该怎么做!我不能连接 lambda 表达式,我知道我可以使用动态表达式,但我认为有更简单的方法吗?知道如何实现吗?


好的,我试过了:

        Func<Customer,bool > a = (bb) => bb.fullName == "asdfsd";
        Func<Customer, bool> b = c => c.lastName == "sdas";
        Func<Customer, bool> cc = c => a(c) && b(c);

又一个问题来了

我将 CC 传递给的方法是 Expression&lt;Func&lt;T, bool&gt;&gt; expression

所以它不起作用给我编译时错误不能在类型之间转换!

【问题讨论】:

    标签: c# linq search lambda


    【解决方案1】:

    您可以创建一些表达式,例如:

    var a = c => c.name == txtName.Text;
    var b = c => c.name == txtName.Text;
    

    然后像这样连接它们:

    var result = c => a(c) && b(c);
    

    【讨论】:

    • 是的,但问题是我会失去智能感知和强类型我试过 var a = (Customer C)=>c.name == txtName.Text;但它给了我编译时错误:无法将 lambda 表达式分配给隐式类型的局部变量
    • @Zeus 这不是您的 lambda 表达式的错误,而只是指定您要在您的情况下创建的委托的类型的要求,您可以适当地编写 Predicate 或 Func。不,你不要失去类型安全。 唯一的是动态的。
    【解决方案2】:

    像这样:

    Func<Customer, bool> predicate = c => true;
    
    if (txtName.Text.Trim() != "")
       predicate = Concatenate(predicate, c => c.Name == txtName.text);
    if (txtEmail.Text.Trim() != "")
       predicate = Concatenate(predicate, c => c.Email == txtEmail.text);
    
    
    
    static Func<T, bool> Concatenate(Func<T, bool> a, Func<T, bool> b) {
        return t => a(t) && b(t);
    }
    

    Concatenate 方法必须是一个单独的方法,因为 lambda 表达式通过引用捕获变量。

    线

    predicate = c => predicate(c) && c.Name == txtName.text;
    

    将导致堆栈溢出,因为predicate 变量将始终引用您分配给它的最新不可变委托实例。

    【讨论】:

    • 为什么会导致堆栈溢出委托是不可变的,所以我希望 RHS 上的谓词引用与分配给 LHS 的对象不同的对象
    • @Rune:lambda 将通过引用对变量进行 fcpature。当它调用predicate(c) 时,predicate 变量将引用变量中的 current 不可变委托实例,即调用的 lambda 表达式。请删除您的反对票。
    【解决方案3】:
    return Customers.Where(c => (txtName.Text.Trim() == "" || c.Name == txtName.Text)
                          && (txtEmail.Text.Trim() == "" || c.Email == txtEmail.Text));
    

    换句话说,只有在“姓名”框填写时才施加“姓名”条件,如果“电子邮件”框被填写,则仅施加“电子邮件”条件。

    请注意,您可以在 .NET 4.0 中使用 String.IsNullOrWhiteSpace 方法,而不是您使用的 Trim 技术。

    【讨论】:

      【解决方案4】:

      我是这样实现的:

         public class LambdaCriteries<T> : List<Expression<Func<T, bool>>>
      {
          public Expression<Func<T, bool>> GetFinalLambdaExpression()
          {
              var par = Expression.Parameter(typeof(T));
              var intial = Expression.Invoke(this.First(),par);
              var sec = Expression.Invoke(this.Skip(1).First(),par);
              BinaryExpression binaryExpression = Expression.And(intial, sec);
              if (this.Count> 2)
              {
                  foreach (var ex in this.ToList().Skip(2))
                  {
                      binaryExpression = Expression.And(binaryExpression, Expression.Invoke(ex, par));
                  }
                  return Expression.Lambda<Func<T, bool>>(binaryExpression,par);
              }
              else
              {
                  return Expression.Lambda<Func<T, bool>>(binaryExpression,par);
              }
      
          }
      }
      

      并使用它:

                 if(txtId.text != "")
                      criteries.Add(v => v.Id == int.Parse(txtId.text));
                 if(txtName.text != "")
                      criteries.Add(v => v.Name == txtId.text);
      

      最后的表达:

      var finalexp = criteries.GetFinalLambdaExpression();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-02
        • 1970-01-01
        • 2015-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多