🤨

[C#] BがAを継承しているのか(型変換が可能か)を判定する

2022/08/27に公開

型のテスト演算子isを用いる

var b = new B();
var bIsA = b is A;
if (bIsA) {
  // 変数bはAから継承した
  // 変数bはインターフェースAを持つ
  // 変数bはAへの暗黙的な参照変換を持つ
  // 変数bはnullではない
}

sharplab.io

is演算子は左辺が右辺との間に互換性があるかを調べます。調べた結果は真偽値(bool)で返却されます。互換性がある場合はtrueです。

`if(b is A a)` という書き方

C#7.0以降、is演算子は宣言パターンに対して照合できます。宣言パターンを使用すると、今まで変数を宣言してキャスト、またはas演算子を用いてnullチェックを行う、といった書き方とは別の書き方ができます。

var b = new B();
if (b is A a) {
  // if文内で変数aが、クラスまたはインターフェースAとして振舞う
  a.RunOnlyA();
} else {
  // if文内で変数aが、クラスまたはインターフェースAとして振舞えない
}
var b = new B();
if (!(b is A a)) {
  // if文内で変数aが、クラスまたはインターフェースAとして振舞えない
} else {
  a.RunOnlyA();
}

System.Type クラスの関数を使う

`System.Type.IsSubclassOf`を用いる
System.Type aType = typeof(A);
System.Type bType = typeof(B);
if (bType.IsSubclassOf(aType)) {
  // タイプbはAから継承した
}

sharplab.io

System.Type.IsSubclassOfSystem.Typeを引数に持つ関数です。
引数で渡されたタイプが継承元であるかを返却します。

インターフェースを実装しているのかは判断できません。

`System.Type.IsAssignableTo`を用いる
System.Type aType = typeof(A);
System.Type bType = typeof(B);
if (bType.IsAssignableTo(aType)) {
  // タイプBはAから継承した (あるいは間接的に継承した)
  // タイプBはAというインターフェースを実装している
  System.Console.Write("{0} is assignable to {1}", bType, aType);
}

sharplab.io

System.Type.IsAssignableTo は、引数で渡された型 代入可能かを真偽値で返却します。
そのため、継承元や間接的に継承しているクラスや、インターフェースであっても代入可能であればtrueを返却します。

`System.Type.IsAssignableFrom` を用いる
System.Type aType = typeof(AClass);
System.Type bType = typeof(BClass);
if (aType.IsAssignableFrom(bType)) {
  // タイプBはAから継承した (あるいは間接的に継承した)
  // タイプBはAというインターフェースを実装している
}

sharplab.io

System.Type.IsAssignableFrom は、丁度 System.Type.IsAssignableToと逆の動きをします。つまり引数に渡された型 代入可能かを真偽値で返却します。

`System.Type.IsInstanceOfType` を用いる
var b = new BClass();
System.Type aType = typeof(AClass);
if (aType.IsInstanceOfType(b)) {
  // 変数bはAから継承した (あるいは間接的に継承した)
  // 変数bはAというインターフェースを実装している
  // 変数bがnullである
}

sharplab.io

System.Type.IsInstanceOfType は引数で渡された変数 b が継承可能であったり、インターフェースが実装されている場合にtrueを返却します。

説明

C#では、型変換したい変数が、指定された型に型変換できなかった場合の対策として is 演算子を用いることができます。
if 文と組み合わせることによって、変換できた場合と変換できなかった場合という書き方ができます。

一方で、System.Typeには引数で渡された型(または変数)がどういう継承関係にあるのか、(あるいはインターフェースが実装されたのか)を判定する方法があります。
System.Typeだけを扱いたい場合はこちらの方法を使います。

多くの場合 `is` 演算子の判定で十分です

is 演算子出の書き方と、System.Type.IsInstanceOfType での書き方を比較すると、
is演算子のほうが英語の文章に近い書き方なので、読みやすいです。

is演算子
var b = new B();
if (b is A) {
  // ...
}
System.Type.IsInstanceOfType
var b = new B();
if (typeof(A).IsInstanceOfType(b)) {
  // ...
}

参考

GitHubで編集を提案

Discussion