Effective C# 3rd 読書メモ 19 実行時型チェックを使ってジェネリックのアルゴリズムを特化させる

以下のコードは、通常の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>として呼び出された場合に使用する、といった特化の仕方も考えられる。
このように、実行時型チェックによって、渡された型に応じた最適な処理を実装できる。

コメントを残す

コメントを残す