2010-08-10 1 views
4

Допустим, у меня есть формы, которые имеют следующее:лямбда-выражения и поиск

Имя: TextBox
Email: TextBox
Возраст: TextBox

теперь я хочу, чтобы получить клиентов Коллекцию на основе этого текстового поля фильтра

поэтому я хочу использовать что-то вроде:

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; 

, как мне это сделать! я не могу конкатенировать лямбда-выражения, я знаю, что могу использовать динамические выражения, но я думаю, что есть более простой способ? любая идея, как это реализовать?


ок я попытался это:

 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<Func<T, bool>> expression

так он не работает дает мне времени компиляции ошибки косяк конвертировать между типами!

ответ

1

Вот как я Реализовано это:

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

вы можете создать некоторые выражения, как:

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

, а затем объединить их, как это:

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

да, но проблема в том, как я буду терять intelisense и строго типизировано, я попробовал var a = (Customer C) => c.name == txtName.Text; , но он дал мне компиляцию ошибки времени: Невозможно назначить лямбда-выражения для неявно типизированных локальных переменной – Stacker

+1

@Zeus, что это не ошибка вашего лямбда-выражения, а просто требование specifiing типа делегата вы хотите создайте в своем случае, вы можете использовать пиджак или Func . и никакие yoo не потеряют безопасность типа. _only_, чтобы потерять, что является динамическим. –

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 должен быть отдельный метод потому что лямбда-выражения захватывают переменные по ссылке.

Линия

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

приведет к переполнению стека, так как переменная predicate всегда будет относиться к последней инстанции неизменен делегата, присвоенным ему.

+1

Почему это приведет к тому, что делегаты переполнения стека будут неизменными, поэтому я ожидаю, что предикат RHS будет ссылаться на объект differrent, чем тот, который назначен LHS –

+0

@Rune: лямбда будет обрабатывать переменную по ссылке. Когда он вызывает «предикат (c)», переменная «предикат» будет ссылаться на экземпляр делегата _current_ immutable в переменной, которая является вызывающим лямбда-выражением. Пожалуйста, удалите ваш downvote. – SLaks

+0

У меня нет нисходящего –

2
return Customers.Where(c => (txtName.Text.Trim() == "" || c.Name == txtName.Text) 
         && (txtEmail.Text.Trim() == "" || c.Email == txtEmail.Text)); 

Другими словами, только наложить «имя» условие, если опция «имя» заполняется, и только наложить «электронная почта» условие, если поле «электронная почта» заполняется.

Обратите внимание: вы можете использовать метод String.IsNullOrWhiteSpace в .NET 4.0 вместо используемой техники Trim.

Смежные вопросы