The code below won't compile:
Func<Person, bool> theLambda = (p) => p.Year >= 1992;
foreach (Person pers in PersonList.FindAll(theLambda))
{
Console.WriteLine(pers.Name);
}
public class Person
{
public string Name { get; set; }
public int Year { get; set; }
public Person(string Name, int Year )
{
this.Name = Name; this.Year = Year;
}
}
However, if I replace variable "theLambda" directly with the lambda, then it works just fine. What's going on here? (Be gentle, I'm a novice). Thank you so much in advance!
(1) I read the error message, but it doesn't mean anything to me.
(2) Yes, I can make it work with a Predicate by using the compile() keyword, but that's not the issue here.
Edit: why would anyone downvote this? The question wasn't that bad at all as the problem domain is not of a logic nature indeed. Really people.
It works because if you declare the lambda inline the compiler implicitly assigns it the right type, i.e. Predicate<Person>
. You don't have to explicitly tell the compiler the lambda type as it knows already that it should take a Person
and return a bool
if you call FindAll
on a List<Person>
.
foreach (Person pers in PersonList.FindAll(p => p.Year >= 1992))
{
Console.WriteLine(pers.Name);
}
You can also use Enumerable.Where
- LINQ method with the same functionality to make it a bit more readable:
foreach (Person pers in PersonList.Where(p => p.Year >= 1992))
{
Console.WriteLine(pers.Name);
}
From msdn:
When writing lambdas, you often do not have to specify a type for the
input parameters because the compiler can infer the type based on the
lambda body, the parameter’s delegate type, and other factors as
described in the C# Language Specification. For most of the standard
query operators, the first input is the type of the elements in the
source sequence. So if you are querying an IEnumerable<Customer>
, then
the input variable is inferred to be a Customer
object
The confusing part is that a Predicate
is logically a Func
that takes an object of some type T
and returns a bool
, but for some reason this typing doesn't work and you have to use Predicate<T>
. Declaring the lambda function inline avoids this confusion as you just write the lambda body and let the compiler infer the type on its own.
The FindAll expects a Predicate
and not a Function
as seen in the method definition Array.FindAll<T> Method (T[], Predicate<T>)
When you try to pass theLambda
it is trying to pass a Function, when the method expects a Predicate. You can instead try defining theLambda as
Predicate<Person> theLambda = (p) => p.Year >= 1992;
A Predicate is a Function that returns a Boolean and that is what is required by the FindAll method to filter the results.
Based on the answer here, you can do the following.
foreach (Person pers in PersonList.FindAll(new Predicate<Person>(theLambda)))