linq Last()如何工作?

我不明白当前可以为null,最后一个可以是一个对象,而最后一个是LINQ函数。 我以为最后使用GetEnumerator并一直持续到current == null并返回该对象。 但是你可以看到第一个GetEnumerator()。当前为null,最后以某种方式返回一个对象。

linq Last()如何工作?

var.GetEnumerator().Current var.Last() 

从在System.Core.dll上使用Reflector :

 public static TSource Last(this IEnumerable source) { if (source == null) { throw Error.ArgumentNull("source"); } IList list = source as IList; if (list != null) { int count = list.Count; if (count > 0) { return list[count - 1]; } } else { using (IEnumerator enumerator = source.GetEnumerator()) { if (enumerator.MoveNext()) { TSource current; do { current = enumerator.Current; } while (enumerator.MoveNext()); return current; } } } throw Error.NoElements(); } 

Last()将调用GetEnumerator() ,然后继续调用MoveNext() / Current直到MoveNext()返回false,此时它返回Current的最后一个值。 通常,Nullity不用作序列中的终止符。

所以实现可能是这样的:

 public static T Last(this IEnumerable source) { if (source == null) { throw new ArgumentNullException("source"); } using (IEnumerator iterator = source.GetEnumerator()) { if (!iterator.MoveNext()) { throw new InvalidOperationException("Empty sequence"); } T value = iterator.Current; while (iterator.MoveNext()) { value = iterator.Current; } return value; } } 

(这可以用foreach循环实现,但是上面更明确地显示了交互。这也忽略了直接访问最后一个元素的可能性。)

在任何MoveNext()之前,枚举数的第一个值在数组的情况下是索引-1处的项。
您必须执行一次MoveNext才能输入实际的集合。
这样做是为了使枚举器的构造函数不起作用,并且这些构造是有效的:

 while (enumerator.MoveNext()) { // Do Stuff } if(enumerator.MoveNext()) { // Do Stuff } // This is identical to Linq's .Any(), essentially. 

请记住,每次调用GetEnumerator通常/必然不会返回相同的Enumerator 。 此外,因为thing.GetEnumerator()返回一个新的Enumerator ,它将启动未初始化(你还没有调用MoveNext() ), thing.GetEnumerator().Current根据定义, thing.GetEnumerator().Current 始终为null。

(我认为…)

如果你看一下IEnumerator Interface到Remarks部分,他们会说出以下内容:

最初 ,枚举数位于集合中的第一个元素之前在这个位置,Current是未定义的。 因此,在读取Current的值之前,必须调用MoveNext将枚举器前进到集合的第一个元素。

因此,您必须调用MoveNext()一次才能获得第一个项目。 否则你什么也得不到。