Enumerable.ElementAt 的重点是什么?

IEnumerable公开了一个枚举器,因此可以枚举该对象。 此接口公开的索引没有任何内容。 IList与索引有关,因为它公开了IndexOf方法。

那么Enumerable.ElementAt的重点是什么? 我刚刚阅读了这个LINQ扩展方法的文档 :

返回序列中指定索引处的元素。

嗯,是的,这是一个序列 ,而不仅仅是一个IEnumerable 。 阅读评论:

如果源类型实现IList,则该实现用于获取指定索引处的元素。 否则,此方法获取指定的元素。

好的,所以如果具体类型实现了从IList (这是一个实际序列)inheritance的东西,那么它与IndexOf()相同。 如果不是,则迭代直到达到索引。

这是一个示例场景:

 // Some extension method exposed by a lib // I know it's not a good piece of code, but let's say it's coded this way: public static class EnumerableExtensions { // Returns true if all elements are ordered public static bool IsEnumerableOrdered(this IEnumerable value) { // Iterates over elements using an index for (int i = 0; i  value.ElementAt(i + 1)) { return false; } } return true; } } // Here's a collection that is enumerable, but doesn't always returns // its objects in the same order public class RandomAccessEnumerable : IEnumerable { private List innerList; private static Random rnd = new Random(); public RandomAccessEnumerable(IEnumerable list) { innerList = list.ToList(); } public IEnumerator GetEnumerator() { var listCount = this.innerList.Count; List enumeratedIndexes = new List(); for (int i = 0; i < listCount; i++) { int randomIndex = -1; while (randomIndex < 0 || enumeratedIndexes.Contains(randomIndex)) { randomIndex = rnd.Next(listCount); } enumeratedIndexes.Add(randomIndex); yield return this.innerList[randomIndex]; } } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } // Here's some test program internal class Program { private static void Main() { var test0 = new List { 0, 1, 2, 3 }; var test1 = new RandomAccessEnumerable(test0); Console.WriteLine("With List"); Console.WriteLine(test0.IsEnumerableOrdered()); // true Console.WriteLine(test0.IsEnumerableOrdered()); // true Console.WriteLine(test0.IsEnumerableOrdered()); // true Console.WriteLine(test0.IsEnumerableOrdered()); // true Console.WriteLine(test0.IsEnumerableOrdered()); // true Console.WriteLine("With RandomAccessEnumerable"); Console.WriteLine(test1.IsEnumerableOrdered()); // might be true or false Console.WriteLine(test1.IsEnumerableOrdered()); // might be true or false Console.WriteLine(test1.IsEnumerableOrdered()); // might be true or false Console.WriteLine(test1.IsEnumerableOrdered()); // might be true or false Console.WriteLine(test1.IsEnumerableOrdered()); // might be true or false Console.Read(); } } 

因此,由于RandomAccessEnumerable可能以随机顺序返回枚举对象,因此您不能依赖简单的IEnumerable接口来假设您的元素已编入索引。 因此,您不希望将ElementAt用于IEnumerable

在上面的例子中,我认为IsEnumerableOrdered应该需要一个IList参数,因为它意味着元素是一个序列。 我实际上找不到ElementAt方法有用的场景,而且不容易出错。

有许多IEnumerable类型,如数组或列表。 所有IList类型( Array也实现)都有一个索引器 ,您可以使用它来访问特定索引处的元素。

如果序列可以成功转换为IList ,则Enumerable.ElementAt将使用此方法。 否则将被列举。

所以它只是一种方便的方法来访问所有IEnumerable类型的给定索引的元素。

这样做的好处是您可以在以后更改类型而无需更改arr[index]

对于它的价值,这里是反映(ILSpy)方法来certificate我所说的:

 public static TSource ElementAt(this IEnumerable source, int index) { if (source == null) { throw Error.ArgumentNull("source"); } IList list = source as IList; if (list != null) { return list[index]; } if (index < 0) { throw Error.ArgumentOutOfRange("index"); } TSource current; using (IEnumerator enumerator = source.GetEnumerator()) { while (enumerator.MoveNext()) { if (index == 0) { current = enumerator.Current; return current; } index--; } throw Error.ArgumentOutOfRange("index"); } return current; }