2016-12-29 2 views
2

Я написал следующий код, и я не могу понять, почему он возвращает только два элемента, а не все. Похоже, что метод «Где» работает только с последним добавленным методом.Выражение LINQ с несколькими методами

class Person 
{ 
    public int Age { get; set; } 
    public string Name { get; set; } 
} 

class Program 
{ 
    public static bool IsAdult(Person person) 
    { 
     return person.Age > 18; 
    } 

    public static bool MethodTrue(Person person) 
    { 
     return true; 
    } 

    static void Main() 
    { 
     var list = new List<Person> 
     { 
      new Person() { Age = 20, Name = "Artur" }, 
      new Person() { Age = 30, Name = "Adam" }, 
      new Person() { Age = 10, Name = "Wieslaw" }, 
      new Person() { Age = 15, Name = "Michal" } 
     }; 


     Func<Person, bool> predicate = null; 
     predicate += MethodTrue; 
     predicate += IsAdult; 

     var res = list.Where(predicate); 
    } 
} 
+4

Почему вы ожидаете получить все четыре объекта «Личность», когда только два из четырех отвечают критериям, определенным вашим предикатом?Сколько из объектов вы ожидаете 'IsAdult()' для возврата 'true' для? –

ответ

4

Если вы соедините делегатов таким образом, все они будут выполнены, но вы получите результат только от последнего. См Hier об этом с помощью делегатов: https://msdn.microsoft.com/en-us/library/ms173172.aspx

Если делегат имеет возвращаемое значение и/или из параметров, он возвращает возвращаемое значение и параметры метода последнего вызван.

Обратный порядок даст вам все результаты:

Func<Person, bool> predicate = null; 
predicate += IsAdult; 
predicate += MethodTrue; 

Но я не вижу никакого смысла в этом LINQ таким образом. Вы могли бы просто написать

Func<Person, bool> predicate = x=> IsAdult(x) || MethodTrue(x); 

Или &&, это зависит от того, что вы на самом деле хотите достичь.

+2

Если вставить его в обратном порядке, это будет только исправление для полосы. Если логика добавляется в MethodTrue, который отфильтровывает там, это вызовет ту же проблему. Единственная причина, по которой их реверсирование будет работать, - это потому, что этот метод всегда имеет значение true. Истинное исправление сводится к тому, что логическое сравнение вы хотите сделать. –

+1

Молодцы. Ссылка на MSDN - это ключ здесь. Очень интересное поведение. –

+0

Согласованная статья в MSDN гласит, что методы объединения с '+ =' - это не путь, если только вам нужен только конечный результат последнего метода оценки, из-за чего беспокоиться о других методах. –

-2

Когда вы предоставляете две функции в вашем предиката, они оцениваются с побитового AND (&&), что означает, что только те объекты, что обе функции возвращают включены. Поскольку вы отфильтровываете Person объектов 18 и младше с IsAdult(), из этой функции возвращаются только две записи. Это означает, что побитовая операция никогда не вернется больше, чем эти две записи.

+1

оба исполняются, но возвращается только результат последнего, обратный порядок возвращает всех 4 человек. –

+1

Интересно - это проблема, связанная с тем, как оператор '+ =' применяется для функций. Как упоминалось в других ответах, 'Func predicate = x => MethodTrue (x) && IsAdult (x);' возвращает две записи, как я ожидал. –

+0

@RickLiddle Нет, речь идет не о том, как объединяются делегаты, а о том, как вызвать вызов делегата с несколькими методами в списке вызовов и как он определяет, какое значение нужно возвращать в такой ситуации. – Servy

0

Ваш итоговый набор фильтруется на основе вашего предиката. У вас есть предикат: IsAdult, который будет сопоставлять возраст ANDMethodTrue, который всегда будет возвращать true. Поэтому, если возраст людей не прошел проверку age > 18, тогда ваш оператор where не сможет выполнить этот элемент в вашем списке.

Таким образом, ваше предложение where вернет только 2 значения, потому что только 2 человека являются взрослыми в соответствии с вашей логикой в ​​вашей функции IsAdult.

Результат на основе предиката:

var list = new List<Person> 
    { 
     new Person() { Age = 20, Name = "Artur" }, 
     new Person() { Age = 30, Name = "Adam" } 
    }; 

Если вы хотите сделать or (||) заявление, вы можете написать предикат, как следует, чтобы вернуть все значения, как указано Максим Симкин.

Func<Person, bool> predicate = x => IsAdult(x) || MethodTrue(x); 
2

Как вы скопировали два предиката, он заботится только о последнем (второй здесь).

Даже если это не так, MethodTrue() всегда возвращает значение true, и только два человека проходят критерии IsAdult, поэтому он возвращает только два элемента. Кстати, вам не нужна переменная predicate. Вы могли бы написать примерно так:

var res = list.Where(p => MethodTrue(p) && (IsAdult(p))); 
+1

@ Downvoter позаботится объяснить? – Encrypt0r

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