@IT:ジェネリック定義のパラメータを実行時に決定したい。

@IT の記事にここで書いても無駄な気はしてるんですが、あっちに書けないしなぁ

甕星さん:
BOX化を伴わずに値を格納することも出来ます。

この部分だけ実行時の話ぽいですね。メソッドのインターフェスにパラメータ型が直接乗るから Boxing を避けてパラメータを受け渡せるってことでしょう。*1

甕星さん:
実行時に型を決定するのであれば、それは.NET 2003以前からあるobject型を使った格納方法とまったく遜色ありません。
あえてgenericにする必要は無いでしょう。

.NET の Generics では、Java 等とは異なり汎用的な実装に対する実行可能イメージを提供するのではなく、具体的な型パラメータが決定するたびに実行可能イメージを生成しなおします。このため、まったく同じコード*2であっても実行時の各種パフォーマンスが大幅に異なる状態になります。
このため、単純に object 型を対象としていたコンテナクラスをパラメータ型 T に置き換えるだけ、つまり

// int を格納する ArrayList または List<object>
IList list = new List<object>
↓

// int を格納する List<int>
IList list = new List<int>

と変更した場合、IList としてアクセスする時点で強い型付けの恩恵は受けられなくなったり、パラメータの受け渡しにおける Boxing などは防げませんが、IList の各メソッド内の実装における実行パフォーマンスは格段に変化します。*3

いのつちさん:
発想が継承関係のようなイメージで作ったのが、そもそもの使用方法の誤りなんですよね

パラメタライズドタイプなどの名称があるように、Generics における T は型継承ではなく、型やメソッドといったものに対して与えられるパラメータであると考えるのがよいですね。

public int Compare<T>(T a, T b);

みたいな記述は

public int Compare(Type T, object a, object b);

のように、「T という型をパラメータとして与えることで、T という型固有の動きをさせられる」と見るとよいかもしれません。*4

*1:格納されるまで Boxing されないかどうかは、受け取った側の実装次第ってところですね

*2:ソースコードまたは IL イメージ

*3:この例だと、パラメータがヒープ渡しからレジスタ渡しになったり、値の格納後の消費メモリが3分の1以下になるなどの差が発生します

*4:引数や戻値が T 型になることで、型に厳しい言語でタイプセーフなプログラミングが可能というのは差はありますが