Lambda Expressions and searching
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!
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);
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.
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.
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();
精彩评论