虽然我不完全确定你在追求什么,但我认为你在很大程度上是有权利的。如果我正确阅读了您的问题,那么您实际上正在考虑两件事:扩展方法和谓词。
以下是可能有助于理解的内容:您基本上可以自己实现 Where 运算符,一步一步地查看所有部分的位置。一旦您知道引擎盖下的内容,它似乎就不那么神奇了。
假设我们有一系列事物,我们想编写一个方法来帮助我们找出其中哪些事物很棒。这是我们可以做到的一种方法:
static IEnumerable<Thing> ThingsThatAreAwesome(IEnumerable<Thing> things){
List<Thing> ret;
foreach (Thing thing in things) {
if (thing.IsAwesome)
ret.Add(thing);
}
return ret;
}
然后我们会这样称呼:
List<Thing> myThings;
List<Thing> myAwesomeThings = ThingsThatAreAwesome(myThings);
所以这很热心。我们只是遍历我们的列表,看看其中哪些很棒,然后返回符合我们很棒标准的那些。但从语义上讲,它并没有真正为我们做这件事——我们很棒的过滤器太棒了,我们希望能够走到一个事物列表并调用我们的操作符,就好像它是 IEnumerable 本身的实例方法一样.
这就是扩展方法的用武之地。通过一些编译器技巧,它们使我们能够“扩展”类型。所以就像你说的,通过将“this”放在我们方法的 IEnumerable 参数前面,我们现在可以走到我们的列表并要求它像这样过滤自己:
List<Thing> myAwesomeThings = myThings.ThingsThatAreAwesome();
所以 - 这就是扩展方法适合的地方。接下来是“谓词”。
所以我们得到了我们非常棒的过滤器,它很棒,但是我们有一个大脑爆炸:稍微抽象一下,我们刚刚编写的那个方法可以用来过滤任何东西。不仅仅是 Thing 对象的列表,也不仅仅是过滤很棒的东西。
让它适用于任何类型都相当容易,我们只是用IEnumerable<T>
, 而不是IEnumerable<Thing>
- 让它成为一个通用运算符,但让它根据任何标准过滤就更棘手了。该方法应该如何知道如何过滤任何类型?它显然不能——我们的调用代码必须准确地告诉它我们所说的“过滤器”是什么意思——我们想要什么样的过滤器。所以我们给它第二个参数,一个函数指针,它表达了我们所追求的。我们将其称为“谓词”,这只是一种表示返回真或假的代码块的方式。当一切都说完了,它看起来有点像这样。我们将把方法重命名为“Filter”,因为这样可以更好地表达我们现在要做的事情:
static IEnumerable<T> Filter(this IEnumerable<T> list, Func<T,bool> predicate) {
foreach (T item in list) {
if (predicate(item))
yield return item;
}
}
您可以看到,我们实际上并没有做任何与之前的 Awesome 过滤器方法不同的事情——我们仍然只是迭代一个列表,执行某种检查,并返回通过该检查的项目。但是我们已经给自己提供了一种调用代码的方法来准确地表达“检查”应该是什么。
我们基本上仍然只做两件事:迭代列表,并对列表中的每个项目进行某种检查——通过检查的项目会被传回。除了现在该方法并不真正知道它正在运行的检查是什么样的 - 我们告诉它,将那段代码作为参数传递,我们的谓词,而不是将其硬编码到方法本身中。我们让调用者来决定他们希望他们的过滤标准是什么。
所以此时,我们基本上已经有了 LINQ Where 运算符——我们现在可以对任何类型的集合运行查询,所有这些都使用相同的方法。如果你还没有弄乱 lambdas,不要担心——只要知道这是一种非常简洁的代码表达方式,在这种情况下,它告诉我们的过滤器方法我们想要过滤什么:
List<Thing> myThings;
List<Cats> myCats;
var myAwesomeThings = myThings.Filter(thing => thing.IsAwesome);
var myCrazyCats = myCats.Filter(cat => cat.IsCrazy);
foreach (var thing in myAwesomeThings){
Console.WriteLine("This thing is awesome! {0}", thing);
}
foreach (var cat in myCrazyCats){
Console.WriteLine("This cat is crazy! {0}", cat);
}
我希望这有助于巩固一些概念——但如果你真的想深入了解 LINQ,你会想要退出 TekPub 的Mastering LINQ截屏视频。这是一个很棒的逐步介绍。为您提供所有基础知识,然后引导您了解几乎所有操作员。我不能推荐它。