Generics を使って型の情報を取得したいというケースがある。このような時にどのような書き方ができるのかわからなかったので調べてみた。
クラスの階層
Generics のパラメータとして渡されるクラスとして次のようなものを作ってみた。出来ればインターフェイスや、アブストラクトクラスも取得できると嬉しい。また、Namespace とクラス名自体を分離して取得したいというのがよくありがちなユースケースだろう。
public interface IClass
{
string Name { get; set; }
}
public abstract class BaseSomeClass : IClass
{
public string Name { get; set; }
public abstract string Hello();
}
public class SomeClass : BaseSomeClass
{
public override string Hello()
{
return "Hello from SomeClass";
}
}
クラス名自体を取得する
いくつかの方法でクラス名を取得できる。
nameof
nameof
で普通に取得できる。
public string HelloByNameOf<T>()
{
return $"Hello! The parameter is {nameof(T)}";
}
結果
nameof("SomeClass"):SomeClass
typeof
typeof
というメソッドを使うこともできる。最初はこんなコードを書いたけどうまくいかない。
public string HelloByTypeOf<T>()
{
return $"Hello! The parameter is {typeof(T)}";
}
Generic method nameof: Hello! The parameter is T
typeof (改)
こうすればうまくいく。typeof
は戻り値(Type) がありそれを使う。
public string HelloByNameAndNamespace<T>()
{
var type = typeof(T);
return $"Hello! The parameter is Name: {type.Name} Namespace: {type.Namespace}";
}
結果
クラス名もメソッド名もとれる。
Generic method GetType: Hello! The parameter is Name: SomeClass Namespace: ClassNameSpike
インターフェイスと Base クラスの取得
インターフェイスとか、継承元のクラスの名前を取得するのはどうすればいいか? デバッグモードでType を見てみると、いくつかのメソッドが使えることに気づく。
-
BaseType
は継承元のクラスの情報が格納されている。 -
ImplementedInterfaces
は、実装しているインターフェイスの配列を取得することができ、Name
により名前を取得できる。FullName
はネームスペース付き
結論
簡単なサンプルプログラムで Generics の型を取る方法を整理してみた。