C# 什么';s可枚举点。元素at<;t来源>;?

C# 什么';s可枚举点。元素at<;t来源>;?,c#,.net,ienumerable,C#,.net,Ienumerable,IEnumerable公开枚举器,因此可以枚举对象。此接口公开的索引没有任何内容IList是关于索引的,因为它公开了IndexOf方法 那么Enumerable.ElementAt有什么意义呢?我刚刚阅读了这个LINQ扩展方法的简介: 返回序列中指定索引处的元素 嗯,是的,它是关于一个序列,而不仅仅是一个IEnumerable。宣读评论: 如果源类型实现IList,则使用该实现 以获取指定索引处的元素。否则,这种方法 获取指定的元素 好的,如果具体类型实现了从IList继承的东西(这是一个实际的

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

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

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

嗯,是的,它是关于一个序列,而不仅仅是一个
IEnumerable
。宣读评论:

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

好的,如果具体类型实现了从
IList
继承的东西(这是一个实际的序列),那么它与
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();
    }
}
//库公开的某个扩展方法
//我知道这不是一段好代码,但假设它是这样编码的:
公共静态类EnumerableExtensions
{
//如果所有元素都已排序,则返回true
公共静态布尔值IsEnumerableOrdered(此IEnumerable值)
{
//使用索引在元素上迭代
对于(int i=0;ivalue.ElementAt(i+1))
{
返回false;
}
}
返回true;
}
}
//这是一个可枚举的集合,但并不总是返回
//其对象的顺序相同
公共类RandomAccessEnumerable:IEnumerable
{
私有列表;
私有静态随机rnd=新随机();
公共随机访问可枚举(IEnumerable列表)
{
innerList=list.ToList();
}
公共IEnumerator GetEnumerator()
{
var listCount=this.innerList.Count;
List EnumeratedIndex=新列表();
for(int i=0;i
因此,由于
RandomAccessEnumerable
可能会以随机顺序返回枚举对象,因此不能依赖简单的
IEnumerable
接口来假定元素已被索引。因此,您不想将
ElementAt
用于
IEnumerable


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

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

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

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

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

值得一提的是,下面是反射(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;
}
publicstatictsourceelementat(此IEnumerable源代码,int索引)
{
if(source==null)
{
抛出错误。ArgumentNull(“源”);
}
IList list=源作为IList;
如果(列表!=null)
{
返回列表[索引];
}
如果(指数<0)
{
抛出错误.ArgumentOutOfRange(“索引”);
}
t电源电流;
使用(IEnumerator enumerator=source.GetEnumerator())
{
while(枚举数.MoveNext())
{
如果(索引==0)
{
当前=枚举数。当前;
回流;
}
索引--;
}
抛出错误.ArgumentOutOfRange(“索引”);
}
回流;
}

这可能对类型更有意义。这是一个序列,而不仅仅是一个IEnumerable:那么你到底如何定义一个“序列”?对我来说,IEnumerable接口代表一系列元素,不多也不少。。。大多数情况下,IEnumerable中的元素将以相同的顺序返回;您的RandomAccessEnumerable示例过于做作,不可能真正相关。嗯,
LinkedList
是一个序列,但它没有实现
IList
:(只是因为