views:

163

answers:

4

Lets say i have a form which have the following :

Name:TextBox
Email:TextBox
Age:TextBox

now i want to Get customers Collection based on this filter textboxs

so i want to to use something like :

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

now of course i dont know which he will fill and which he wont so

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

how do i do this ! i cant concatenate lambda expressions , i know i can use dynamic expressions but i think there is easier way ? any idea how to implement this ?


ok i tried this:

        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);

now comes another problem

the method im passing CC to is expecting Expression<Func<T, bool>> expression

so it doesnt work gives me compile time error cant convert between types!

+2  A: 

you can create some expressions like:

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

and then concatenate them like this:

var result = c => a(c) && b(c);
valya
yes but problem with that is i will lose intelisense and strongly typed i tried var a = (Customer C)=>c.name == txtName.Text;but it gave me compile time error :Cannot assign lambda expression to an implicitly-typed local variable
Stacker
@Zeus that's not an error of your lambda expression but simply a requirement of specifiing the type of the delegate you're looking to create in your case you could propably write Predicate<T> or Func<T,bool>. and no yoo don't loose type safety. The _only_ to loose that is dynamic.
Rune FS
+2  A: 

Like this:

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);
}

The Concatenate method must be a separate method because lambda expressions capture variables by reference.

The line

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

will result in a stack overflow because the predicate variable will always refer to the latest immutable delegate instance that you assign to it.

SLaks
why would that result in a stack overflow delegates are immutable so I would expect the predicate on the RHS to refererance a differrent object than the one assigned to the LHS
Rune FS
@Rune: The lambda will fcpature the variable by reference. When it calls `predicate(c)`, the `predicate` variable will refer to the _current_ immutable delegate instance in the variable, which is the calling lambda expression. Please remove your downvote.
SLaks
@Slaks I haven't downvoted
Rune FS
+2  A: 
return Customers.Where(c => (txtName.Text.Trim() == "" || c.Name == txtName.Text)
                      && (txtEmail.Text.Trim() == "" || c.Email == txtEmail.Text));

In other words, only impose the 'name' condition if the 'name' box is filled out, and only impose the 'email' condition if the 'email' box is filled out.

Note that you can use the String.IsNullOrWhiteSpace method in .NET 4.0 instead of the Trim technique you have used.

Ani
A: 

Here is how i Implemented it:

   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);
        }

    }
}

and to use it :

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

and final expression :

var finalexp = criteries.GetFinalLambdaExpression();
Stacker