IEnumerable<T>
列挙子を公開するため、オブジェクトを列挙できます。このインターフェイスによって公開されるインデックスについては何もありません。メソッドIList<T>
を公開するため、インデックスに関するものです。IndexOf
では、Enumerable.ElementAt のポイントは何ですか? この LINQ 拡張メソッドのドキュメントを読みました。
シーケンス内の指定されたインデックスにある要素を返します。
ええ、そうです、それはシーケンスについてであり、IEnumerable
. コメントを読む:
ソースのタイプが IList を実装している場合、その実装を使用して、指定されたインデックスの要素を取得します。それ以外の場合、このメソッドは指定された要素を取得します。
さて、具象型が継承するもの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
したがって、 forには使用したくありませんIEnumerable
。
上記の例では、要素がシーケンスであることを意味するIsEnumerableOrdered
ため、パラメーターが必要であると思います。メソッドが便利で、バグが発生しにくいIList<T>
シナリオを実際に見つけることができません。ElementAt