GenericParameter T に何が設定されたか?
LCG 版 Zipper を軽く書いてみようとしたら、これにひっかかった。IEnumerator
public class X<T, U> : Y, IEnumerable<U> {} X<int, string> x = new ...;
例えばこんな場合、x から typeof(string) を得るにはどうすればよいのか?
すぐに思いつくのは、Type.GetGenericArguments() を呼び出すことだけど、ContainsGenericParameters = false で、{ typeof(int), typeof(string) } が返ってきた場合にどうやって IEnumerable のパラメタライズドタイプである typeof(string) を発見するためのインデックス 1 を得ればよいだろうか?
このインデックス値を得るには、Generic 型である typeof(T) や typeof(U) に対して GenericParameterPosition プロパティを参照する必要がある。具体的には、
x.GetGenericTypeDefinition() // X<T, U> 型の .GetInterface(typeof(IEnumerable<>).Fullname) // 実装しているインターフェス IEnumerable<T> の .GetGenericArguments()[0] // 0 番目のパラメータ (== T) の .GenericParameterPosition // 保存場所のインデックス値 // 良い子はエラーチェックとかしようね
となる。型名がわかっているなら、x.GetGenericTypeDefinition() を呼ばずに typeof(X<,>) と記載することもできます。
なお、上記で == T と書いているのは、IEnumerable
また、元の型の GetGenericArguments() の結果からインデックスを引くのではなく、直接
x.GetType() .GetInterface(typeof(IEnumerable<>).Fullname) .GetGenericArguments()[0]
というようにして typeof(string) を得ることも可能になっている。
(最終的にこっちを使うことにした)
また、親クラスにたいして処理をしたい場合には、文中の GetInterface() を BaseType に読み替えるなどして調整してください。