項目19 実行時の型チェックを使用してジェネリックアルゴリズムを特化する
実行時の引数の型に応じ、その型が持つ機能に適したアルゴリズムを使用するようにする。
型引数が適切な機能を備えている場合、より効率的なアルゴリズムを効率的に実装できる。
ジェネリック型のインスタンスは、実行時の型ではなく、コンパイル時におけるオブジェクトの型をもとにして生成されることに注意。
例)一連の要素を逆順にして返すことができるようなクラス
IEnumerable<T>
の機能のみ使用した場合
public sealed class ReverseEnumerable<T> : IEnumerable<T> { //省略 IEnumerable<T> sourceSequence; IList<T> originalSequence; public ReverseEnumerable(IEnumerable<T> sequence) { sourceSequence = sequence; } public IEnumerator<T> GetEnumerator() { if(originalSequence == null) { originalSequence = new List<T>(); foreach(T item in sourceSequence) originalSequence.Add(item); } return new ReverseEnumerator(originalSequence); } //省略 }
IEnumerable<T>
はランダムアクセスをサポートしてない。逆順に操作するために、ランダムアクセス可能な型(List<T>
)を作成している。
IListの機能を使用する場合
public ReverseEnumerable(IEnumerable<T> sequence) { sourceSequence = sequence; originalSequence = sequence as IList<T>; }
入力sequence
がIList<T>
をサポートしている場合、ランダムアクセス可能なためList<T>
の作成は不要。上記のように修正すれば、IList<T>
をサポートしている場合はoriginalSequence
がnullではなくなるのでif(originalSequence == null)
のブロックが実行されない。
他、ICollection
を実装しているなら.Count
を利用してして宣言時に必要なメモリを確保(new List<T>(source.Count)
)して効率をよくする、など。