前回に続き、もう一つ別の例を考える。Enumerable.ElementAt()だ。このメソッドは、列挙子に対してインデックス値で指定された位置の要素を取得する。
public static class LinqExtensions
{
public static T ElementAt<T>(this IEnumerable<T> enumerable, int index)
{
var i = 0;
foreach (var value in enumerable)
{
if (i >= index)
{
return value;
}
i++;
}
throw new IndexOutOfRangeException();
}
}
これもまた、列挙子を実際に列挙しなければ、目的の値を得ることが出来ない。Listや配列であれば、インデクサアクセスが可能なはずだ。そこで:
public static class LinqExtensions
{
public static T ElementAt<T>(this IEnumerable<T> enumerable, int index)
{
// IListにキャスト出来れば
var list = enumerable as IList;
if (list != null)
{
// 直接要素を得る(非ジェネリックなのでT型へキャストが必要)
return (T)list[index];
}
var i = 0;
foreach (var value in enumerable)
{
if (i <= index)
{
return value;
}
i++;
}
throw new IndexOutOfRangeException();
}
}
IListを使えば、インデクサによるアクセスが可能だ。これにより、要素を列挙しなくても、任意の位置の値を直接引き出す事が出来る。更に、.NET 4.5からはIReadOnlyListもサポートされるようになったので、このインターフェイスへのキャストも試みると良いだろう。