以下のコードは、通常のEnumerable<T>
とは逆順に走査を行う、ReverseEnumerable<T>
の実装である、
ここでは、以下の工夫によってコピーの回数を減らし、パフォーマンスを向上させている。
IList<T>
を実装している型はそのまま利用するICollection<T>
を実装している型からサイズを取得する
public sealed class ReverseEnumerable<T> : IEnumerable<T>
{
private class ReverseEnumerator : IEnumerator<T>
{
private int _currentIndex;
private readonly IList<T> _collection;
public ReverseEnumerator(IList<T> collection)
{
_collection = collection;
_currentIndex = collection.Count;
}
public void Dispose()
{
// なにもしないけど必要
}
// 1つずつ順にポインタを前にすすめる
public bool MoveNext() => --_currentIndex >= 0;
public void Reset() => _currentIndex = _collection.Count;
public T Current => _collection[_currentIndex];
object IEnumerator.Current => Current;
}
private readonly IEnumerable<T> _sequence;
public ReverseEnumerable(IEnumerable<T> sequence)
{
_sequence = sequence;
}
public IEnumerator<T> GetEnumerator()
{
var list = _sequence as IList<T>;
if (list != null)
// sequenceがIListを実装しているなら、そのまま利用する
return new ReverseEnumerator(list);
// sequenceがIListを実装していないので、Listに変換
var col = _sequence as ICollection<T>;
list = col != null ? new List<T>(col.Count) : new List<T>();
foreach (var item in _sequence)
list.Add(item);
return new ReverseEnumerator(list);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
さらに特化させる方法として、文字列を逆順に操作するためのReverseStringEnumerable<T>
を定義し、ReverseEnumerable<string>
として呼び出された場合に使用する、といった特化の仕方も考えられる。
このように、実行時型チェックによって、渡された型に応じた最適な処理を実装できる。