了解C#编译器如何处理链接linq方法
我正在尝试围绕C#编译器在链接
linq方法时所做的事情,特别是在多次链接同一方法时.
简单的例子:假设我试图根据两个条件过滤一系列int. 最明显的事情是这样的: IEnumerable<int> Method1(IEnumerable<int> input) { return input.Where(i => i % 3 == 0 && i % 5 == 0); } 但我们也可以链接where方法,每个方法都有一个条件: IEnumerable<int> Method2(IEnumerable<int> input) { return input.Where(i => i % 3 == 0).Where(i => i % 5 == 0); } 我看了反射器中的IL;这两种方法明显不同,但目前我不知道进一步分析它:) 我想找出: 解决方法
(a)的答案很简短,但我将在下面详细介绍:
编译器实际上并不进行链接 – 它通过对象的正常组织在运行时发生!这里的魔力远不如乍看之下 – Jon Skeet recently completed the “Where clause” step在他的博客系列中重新实现LINQ to Objects.我建议你仔细阅读. 在很短的时间内,会发生这样的情况:每次调用Where扩展方法时,它都会返回一个新的WhereEnumerable对象,它有两个东西 – 对前一个IEnumerable的引用(你调用的那个),以及你提供的lambda . 当你开始迭代这个WhereEnumerable时(例如,在你的代码中的foreach中),在内部它只是开始迭代它引用的IEnumerable.
这一直沿着链条向下直到我们击中原点,这实际上是某种阵列或真实元素的存储.当每个Enumerable然后说“OK,这是我的元素”将它传递回链时,它也应用它自己的自定义逻辑.对于Where,它应用lambda来查看元素是否通过了条件.如果是这样,它允许它继续到下一个调用者.如果失败,则在该点停止,返回其引用的Enumerable,并请求下一个元素. 这种情况一直持续到每个人的MoveNext都返回false,这意味着枚举已经完成,并且没有更多的元素. 要回答(b),总会有不同之处,但是这里太麻烦了.别担心:) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |