我对LINQ的谓词理解正确吗

我对LINQ的谓词理解正确吗,linq,language-theory,Linq,Language Theory,我正试图了解谓词和LINQ 虽然LINQ的语法对我来说已经开始有意义了,但我在LINQ背后的理论方面遇到了更多的问题 这是我到目前为止所拥有的。在设计LINQ时,Microsoft没有创建一个新的接口来定义可以使用LINQ查询的任何对象需要实现的每个成员,而是决定采用现有的类IEnumerable,并使用扩展方法扩展该类 我想我了解扩展方法。扩展方法是静态类中的静态方法。传入此方法的第一个参数与this参数一起传入,并定义要扩展的类型。然后,与扩展方法位于同一命名空间内的任何此类实例都可以使用该

我正试图了解谓词和LINQ

虽然LINQ的语法对我来说已经开始有意义了,但我在LINQ背后的理论方面遇到了更多的问题

这是我到目前为止所拥有的。在设计LINQ时,Microsoft没有创建一个新的接口来定义可以使用LINQ查询的任何对象需要实现的每个成员,而是决定采用现有的类IEnumerable,并使用扩展方法扩展该类

我想我了解扩展方法。扩展方法是静态类中的静态方法。传入此方法的第一个参数与
this
参数一起传入,并定义要扩展的类型。然后,与扩展方法位于同一命名空间内的任何此类实例都可以使用该方法

因此,Microsoft在System.LINQ命名空间内创建了许多扩展IEnumerable的扩展方法,任何使用System.LINQ命名空间并包含实现IEnumerable的对象的类都可以使用这些扩展方法来查询该对象。每个扩展方法都将委托作为其第二个参数

对于
where
where
是扩展IEnumerable并返回实现IEnumerable的新对象的扩展方法。下一个参数
采用的是Func(泛型Func)类型的谓词(返回布尔值的方法)。这是一个委托,它返回true或false,最多可以使用16个参数。但是,不必编写满足此条件的方法,而是创建Func类型的实例并将其指向您的方法,并将此变量传递到
方法中,其中
方法允许您动态编写。构建LINQ查询时,在单词
之后放置的所有内容都将成为谓词

在幕后,对实现IEnumerable的对象的成员进行迭代并根据谓词进行求值,如果
true
,则使用
yield return
语法将其添加到新的IEnumerable对象中


道歉,如果这看起来有点脱节,但我基本上把所有的东西都从我的脑子里抛了出来,因为我理解它,我希望有人比我更了解这一点,会来告诉我我有哪些地方是正确的,哪些部分是错误的,并且通常会扩展到我上面所写的内容,因为我在正确理解这里发生的事情方面有点困难。

虽然我不完全确定您的目标,但我认为您在很大程度上是正确的。如果我没有看错你的问题,那么这里确实有两件事你在思考:扩展方法和谓词

下面是可能有助于理解这一点的方法:基本上,您可以自己一步一步地实现Where操作符,并查看所有片段的位置。一旦你知道引擎盖下面是什么,它看起来就不那么神奇了

假设我们有一系列的东西,我们想写一个方法来帮助我们找出哪些东西是很棒的。我们有一种方法可以做到:

static IEnumerable<Thing> ThingsThatAreAwesome(IEnumerable<Thing> things){
    List<Thing> ret;
    foreach (Thing thing in things) {
        if (thing.IsAwesome)
            ret.Add(thing);
    }

    return ret;
}
静态IEnumerable things部分(IEnumerable things){
列表ret;
foreach(事物中的事物){
如果(我喜欢的东西)
重新添加(事物);
}
返回ret;
}
我们可以这样称呼它:

List<Thing> myThings;
List<Thing> myAwesomeThings = ThingsThatAreAwesome(myThings);
List<Thing> myAwesomeThings = myThings.ThingsThatAreAwesome();
列举神话;
列出myAwesomeThings=某些领域的事物(神话);
所以这是相当热切的。我们只是重复我们的列表,看看其中哪些是很棒的,然后返回那些符合我们很棒标准的。但从语义上讲,它并不能真正为我们做到这一点——我们的Aweasome过滤器非常棒,我们希望能够直接找到一个列表并调用它的运算符,就好像它是IEnumerable本身的一个实例方法一样

这就是扩展方法的用武之地。通过一些编译器技巧,它们使我们能够“扩展”类型。正如您所说,通过将“this”放在方法的IEnumerable参数前面,我们现在可以走到我们的列表,并要求它像这样过滤自己:

List<Thing> myThings;
List<Thing> myAwesomeThings = ThingsThatAreAwesome(myThings);
List<Thing> myAwesomeThings = myThings.ThingsThatAreAwesome();
List myAwesomeThings=myThings.thingsthattareawesome();
所以-这就是扩展方法适合的地方。接下来是“谓词”

我们有一个很棒的过滤器,它很棒,但是我们有一个大脑爆炸:通过一点抽象,我们刚刚写的方法可以用来过滤任何东西。不仅仅是事物对象的列表,也不仅仅是对令人敬畏的事物进行过滤

使它与任何类型一起工作是相当容易的,我们只是使它成为一个带有
IEnumerable
的泛型运算符,而不是
IEnumerable
——但使它在任何条件下都进行过滤更为棘手。该方法如何知道如何过滤任何类型?它显然不能——我们的调用代码必须准确地告诉它我们所说的“过滤器”是什么意思——我们想要什么类型的过滤器。所以我们给它第二个参数,一个函数指针,它表达了我们所追求的。我们将其称为“谓词”,这只是表示返回true或false的代码块的一种方式。当一切都说了又做了,它看起来有点像这样。我们将该方法重命名为“Filter”,因为它更好地表达了我们现在要做的事情:

static IEnumerable<T> Filter(this IEnumerable<T> list, Func<T,bool> predicate) {
    foreach (T item in list) {
        if (predicate(item))
            yield return item;
    }
}
静态IEnumerable筛选器(此IEnumerable列表,Func谓词){
foreach(列表中的T项){
if(谓语(项))
收益回报项目;
}
}
您可以看到,我们实际上并没有做任何与以前可怕的过滤器方法不同的事情——我们仍然只是在列表上迭代,执行某种检查,并返回通过该检查的项目。但我们已经为自己提供了一种调用代码的方法,以准确地表示“检查”应该是什么

我们基本上仍然只做两件事:迭代o