假设我有以下代码:
var X = XElement.Parse (@" <ROOT> <MUL v='2' /> <MUL v='3' /> </ROOT> "); Enumerable.Range (1,100) .Select (s => X.Elements () .Select (t => Int32.Parse (t.Attribute ("v").Value)) .Aggregate (s,(t,u) => t * u) ) .ToList () .ForEach (s => Console.WriteLine (s));
什么是.NET运行时实际在这里做什么?它是解析并将属性转换为100次中的每一个整数,还是足够智能,以确定它应该缓存解析的值而不重复该范围中每个元素的计算?
而且,我怎么会自己搞清楚这样的事情呢?
在此先感谢您的帮助.
解决方法
自从我挖掘这段代码以来已经有一段时间了,但是,IIRC,Select工作的方式就是简单地缓存你提供它的Func并一次在源集合上运行它.因此,对于外部范围中的每个元素,它将运行内部Select / Aggregate序列,就像它是第一次一样.没有任何内置缓存 – 您必须在表达式中自己实现.
如果你想自己解决这个问题,你有三个基本选择:
>编译代码并使用ildasm查看IL;它是最准确的,特别是对于lambdas和闭包,你从IL获得的东西可能看起来与你放入C#编译器的东西完全不同.
>使用像dotPeek这样的东西将System.Linq.dll反编译成C#;再一次,你从这些工具中获得的东西可能只是大致类似于原始的源代码,但至少它将是C#(特别是dotPeek做得非常好,并且是免费的.)
>我的个人偏好 – 下载.NET 4.0 Reference Source并自己寻找;这就是它的用途:)您必须只信任MS,参考源与用于生成二进制文件的实际源匹配,但我认为没有任何理由怀疑它们.>正如@AllonGuralnek所指出的,你可以在一行内的特定lambda表达式上设置断点;将光标放在lambda体内的某个位置并按F9,它将断点为lambda. (如果你做错了,它会突出显示断点颜色的整行;如果你做得对,它只会突出显示lambda.)