gpt4 book ai didi

c# - Enumerable.ElementAt 有什么意义?

转载 作者:太空狗 更新时间:2023-10-29 21:40:18 27 4
gpt4 key购买 nike

IEnumerable<T>公开一个枚举器,因此可以枚举对象。此接口(interface)公开的索引没有任何内容。 IList<T>关于索引,因为它公开了 IndexOf方法。

那么 Enumerable.ElementAt 有什么意义呢?我刚读了doc这个 LINQ 扩展方法:

Returns the element at a specified index in a sequence.

嗯,是的,它是关于一个序列,而不仅仅是一个IEnumerable .阅读备注:

If the type of source implements IList, that implementation is used to obtain the element at the specified index. Otherwise, this method obtains the specified element.

好吧,如果具体类型实现了继承自 IList<T> 的东西(这是一个实际序列),那么它与 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<int> value)
{
// Iterates over elements using an index
for (int i = 0; i < value.Count() - 1; i++)
{
if (value.ElementAt(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<T> : IEnumerable<T>
{
private List<T> innerList;
private static Random rnd = new Random();

public RandomAccessEnumerable(IEnumerable<T> list)
{
innerList = list.ToList();
}

public IEnumerator<T> GetEnumerator()
{
var listCount = this.innerList.Count;
List<int> enumeratedIndexes = new List<int>();

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<int> { 0, 1, 2, 3 };
var test1 = new RandomAccessEnumerable<int>(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<T>假设您的元素已被索引的界面。所以你不想使用 ElementAt对于 IEnumerable .

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

最佳答案

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

如果序列可以成功转换为 IListEnumerable.ElementAt 将使用它。否则会被枚举。

因此,对于所有类型的 IEnumerable 类型,它只是一种访问给定索引处元素的便捷方式。

这样做的好处是您可以稍后更改类型,而无需更改 arr[index] 的所有出现。

对于它的值(value),这里是 reflected(ILSpy) 方法来演示我所说的内容:

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

关于c# - Enumerable.ElementAt<TSource> 有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14338680/

27 4 0