C#で子クラスのTypeから継承元インタフェースのジェネリック引数を得る方法

外部で定義された型のインスタンスに対してアレコレするフレームワークを作っている時、 ジェネリクスで指定された型が知りたくなる時がある。

言語はC#。

"How to detect Type of generic property, in other words generic argument, from derived class"
https://gist.github.com/kazyx/9cdc033dd3bf19724b5253c759705a8f


わかりやすく言うと、typeof(MyFoo) から typeof(Foo) を得たい。
public interface MyInterface<T> {
    T MyParameter { set; get; }
}

public class Foo {
    public string Bar { set; get; }
}

public class MyFoo : MyInterface<Foo> {
    public Foo MyParameter { set; get; }
}

1. プロパティ名やフィールド名から辿る


インタフェースがジェネリック引数型のプロパティやフィールドを定義している場合、それをリフレクションで引いてくれば型情報が得られる。
public Type GetTypeOfGenericArgByPropertyName(Type derivedClassType) {
    var myParamPropertyInfo = derivedClassType.GetProperty(nameof(MyInterface.MyParameter));

    // If derivedClassType is 'MyFoo', myParamPropertyInfo is PropertyInfo of MyFoo.MyParameter
    return myParamPropertyInfo.PropertyType;
}
C#6 以降のモダンな環境であれば nameof が使えるのでこれでもまあ良いかもしれない。
それより前だと GetProperty("MyParameter") とする必要があり微妙。

2. ジェネリックインタフェースの型情報から辿る


ジェネリック引数を含んだの継承元インタフェース型をリフレクションで得ることができるので、そこからジェネリック引数として取得する。
public Type GetTypeOfGenericArg(Type derivedClassType) {
    var typedMyInterfaceType = derivedClassType.GetInterface(typeof(MyInterface<>).FullName);

    // If derivedClassType is 'MyFoo', typedMyInterfaceType is typeof(MyInterface)
    return typedMyInterfaceType.GetGenericArguments()[0];
}
こっちの方法であれば、Unity とかの古い C# 環境でも使える。

ちなみに、typeof(MyInterface<>).FullName"MyInterface`1" らしい。
https://msdn.microsoft.com/ja-jp/library/ayfa0fcd(v=vs.110).aspx
For generic interfaces, the name parameter is the mangled name, ending with a grave accent (`) and the number of type parameters. This is true for both generic interface definitions and constructed generic interfaces. For example, to find IExample<T> (IExample(Of T) in Visual Basic) or IExample<string> (IExample(Of String) in Visual Basic), search for "IExample`1".

おわり。

コメント

このブログの人気の投稿

Lumia 920買った - LTE有効化と開発端末登録

Android で Unicode絵文字入力

Nexus 5 買った