Лямбда-выражения и поиск

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

Имя:TextBox
Электронная почта: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

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


person Stacker    schedule 10.08.2010    source источник


Ответы (4)


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

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

а затем объединить их следующим образом:

var result = c => a(c) && b(c);
person Valentin Golev    schedule 10.08.2010
comment
да, но проблема в том, что я потеряю intelisense и сильно напечатаю, я пробовал var a = (Customer C)=›c.name == txtName.Text; но это дало мне ошибку времени компиляции: невозможно назначить лямбда-выражение неявно типизированной локальной переменной - person Stacker; 10.08.2010
comment
@Zeus, это не ошибка вашего лямбда-выражения, а просто требование указать тип делегата, который вы хотите создать, в вашем случае вы могли бы написать Predicate‹T› или Func‹T, bool›. и нет, не теряйте безопасность типов. единственное, которое можно потерять, является динамическим. - person Rune FS; 10.08.2010

Нравится:

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

person SLaks    schedule 10.08.2010
comment
почему это приводит к тому, что делегаты переполнения стека неизменяемы, поэтому я ожидаю, что предикат на RHS будет ссылаться на другой объект, чем тот, который назначен LHS - person Rune FS; 10.08.2010
comment
@Rune: лямбда вычислит переменную по ссылке. При вызове predicate(c) переменная predicate будет ссылаться на текущий экземпляр неизменяемого делегата в переменной, которая является вызывающим лямбда-выражением. Пожалуйста, удалите свой отрицательный голос. - person SLaks; 10.08.2010

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

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

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

person Ani    schedule 10.08.2010

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

   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();
person Stacker    schedule 15.08.2010