简体   繁体   English

Lambda可在FindAll中使用,但不能用作Func(或Expression)使用

[英]Lambda works in FindAll, but not when using it as an Func (or Expression)

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. 但是,如果我直接用lambda替换变量“ theLambda”,则它可以正常工作。 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. (1)我阅读了错误消息,但对我来说没有任何意义。
(2) Yes, I can make it work with a Predicate by using the compile() keyword, but that's not the issue here. (2)是的,我可以通过使用compile()关键字使其与谓词一起使用,但这不是问题。

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, ie Predicate<Person> . 之所以起作用,是因为如果您声明内联lambda,则编译器会隐式为其分配正确的类型,即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> . 您不必显式地告诉编译器lambda类型,因为它已经知道如果在List<Person>上调用FindAll ,则应该使用Person并返回bool

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: 您还可以使用Enumerable.Where具有相同功能的LINQ方法,使其更具可读性:

foreach (Person pers in PersonList.Where(p => p.Year >= 1992))
{
    Console.WriteLine(pers.Name);
}

From msdn : 来自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. 编写Lambda时,通常不必为输入参数指定类型,因为编译器可以根据Lambda主体,参数的委托类型和C#语言规范中所述的其他因素来推断类型。 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 因此,如果要查询IEnumerable<Customer> ,则将输入变量推断为Customer对象

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> . 令人困惑的部分是, Predicate在逻辑上是一个Func ,它接受某个T类型的对象并返回bool ,但是由于某种原因,此类型无效,您必须使用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. 内联声明lambda函数可避免这种混淆,因为您只需编写lambda主体,然后让编译器自行推断类型。

The FindAll expects a Predicate and not a Function as seen in the method definition Array.FindAll<T> Method (T[], Predicate<T>) FindAll需要一个Predicate而不是Function定义,如方法定义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. 当您尝试传递theLambda它会尝试传递一个Function,而该方法需要一个谓词。 You can instead try defining theLambda as 您可以尝试将theLambda定义为

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. 谓词是一个返回布尔值的函数,它是FindAll方法过滤结果所需要的。

根据此处的答案,您可以执行以下操作。

foreach (Person pers in PersonList.FindAll(new Predicate<Person>(theLambda)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM