[C# クラス] キャストで型変換(基底クラス⇔派生クラス)

[C# クラス] 仮想メソッドを使った多態性(ポリモーフィズム)の話では基底クラス型の変数に派生クラスのインスタンスを入れることができると書きました。

その基底クラス型の変数から呼び出せるのは基底クラスにあるメンバーだけになります。では、派生クラスにある独自のメンバーにアクセスするにはどうすればいいのか?
今回はそのあたりの話をします。

派生クラスにある独自のメンバーにアクセスするには、派生クラス型に型変換してから独自のメンバーにアクセスします。

変換する方法はいくつかあります。

スポンサーリンク

キャスト式で変換する

キャスト式はこんな感じに書きます。式の結果は変換された値です。

(変換したい型名)変数;

キャスト式は指定された型に変換できない場合、エラーになるので注意してください。

基底クラスから派生クラスへの変換をアップキャスト
派生クラスから基底クラスへの変換をダウンキャスト といいます。

ダウンキャストするときにはキャスト式は必要ありません。そのまま代入することができます。キャスト式が必要なのはアップキャストする場合です。

using System;
// 基底クラス
class BaseClass
{
    // 仮想メソッド
    public virtual void Method() => Console.WriteLine("基底クラスのメソッドです");
}
// 派生クラス
class SampleClass : BaseClass
{
    // 派生クラス独自のメソッド
    public void OriginalMethod() => Console.WriteLine("派生クラス独自のメソッドです");
}
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れる
        BaseClass b = new SampleClass();

        // キャスト式を使って派生クラス型に変換する
        SampleClass s = (SampleClass)b;
        // 派生クラスのメソッドを呼び出す
        s.OriginalMethod();
    }
}
派生クラス独自のメソッドです

また、こんな感じに丸かっこ ( ) でキャスト式を囲ってメンバーを呼び出すこともできます。

((SampleClass)b).OriginalMethod();
スポンサーリンク

as を使って変換する

as はこんな感じに書きます。式の結果は変換された値です。

変換したい変数 as 変換したい型名;

as を使って変換できるのは、参照型(クラス)とNull許容型になります。

using System;
// 基底クラス
class BaseClass
{
    // 仮想メソッド
    public virtual void Method() => Console.WriteLine("基底クラスのメソッドです");
}
// 派生クラス
class SampleClass : BaseClass
{
    // 派生クラス独自のメソッド
    public void OriginalMethod() => Console.WriteLine("派生クラス独自のメソッドです");
}
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れる
        BaseClass b = new SampleClass();

        // as を使って派生クラス型に変換する
        SampleClass s = b as SampleClass;
        // 派生クラスのメソッドを呼び出す
        s.OriginalMethod();
    }
}
派生クラス独自のメソッドです

as は指定された型に変換できなかった場合、nullが返ってきます。
nullだったら処理しないとかやりたい場合は、型パターンマッチングを使います。

スポンサーリンク

型パターンマッチングを使う

パターンマッチングはこんな感じに書きます。

変換したい変数 is 変換したい型名 変換した値を入れる変数;

式の結果は変換できる場合にTrue、できない場合にFalseが返ってきます。
そして一番後ろに書いた変数に変換された値が入ります。

こんな感じに変換できたかチェックしつつ、メソッドを呼び出すことができます。

using System;
// 基底クラス
class BaseClass
{
    // 仮想メソッド
    public virtual void Method() => Console.WriteLine("基底クラスのメソッドです");
}
// 派生クラス
class SampleClass : BaseClass
{
    // 派生クラス独自のメソッド
    public void OriginalMethod() => Console.WriteLine("派生クラス独自のメソッドです");
}
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れる
        BaseClass b = new SampleClass();

        // 型パターン マッチング
        if (b is SampleClass s)
        {
            // 派生クラスのメソッドを呼び出す
            s.OriginalMethod();
        }
    }
}
派生クラス独自のメソッドです
スポンサーリンク

型の判定について

is で変換できると判定される(true返ってくる)のは次のような感じです。
A is B とした場合、

  • Aに入っているインスタンスの型と指定された型(B)が同じ場合
基底クラス A = new 派生クラス();     // Aには派生クラス型のインスタンスが入っている
Console.WriteLine(A is 派生クラス);  // trueになる
  • Aに入っているインスタンスの型が指定された型(B)から派生している場合
派生クラス A = new 派生クラス();     // Aには派生クラス型のインスタンスが入っている
Console.WriteLine(A is 基底クラス);  // trueになる

調べたコードはこんな感じ。

using System;

// 基底クラス
class BaseClass { }
// 派生クラス
class ChildClass : BaseClass { }
// 派生クラスの派生クラス
class GrandChildClass : ChildClass { }

// メインプログラム
class Program
{
    public static void Main()
    {
        BaseClass b = new BaseClass();
        Console.WriteLine("BaseClass b = new BaseClass();");
        Console.WriteLine($"b is BaseClass       = {b is BaseClass}");
        Console.WriteLine($"b is ChildClass      = {b is ChildClass}");
        Console.WriteLine($"b is GrandChildClass = {b is GrandChildClass}");

        b = new ChildClass();
        Console.WriteLine("\nBaseClass b = new ChildClass();");
        Console.WriteLine($"b is BaseClass       = {b is BaseClass}");
        Console.WriteLine($"b is ChildClass      = {b is ChildClass}");
        Console.WriteLine($"b is GrandChildClass = {b is GrandChildClass}");

        b = new GrandChildClass();
        Console.WriteLine("\nBaseClass b = new GrandChildClass();");
        Console.WriteLine($"b is BaseClass       = {b is BaseClass}");
        Console.WriteLine($"b is ChildClass      = {b is ChildClass}");
        Console.WriteLine($"b is GrandChildClass = {b is GrandChildClass}");
    }
}

実行結果はこんな感じです。

BaseClass b = new BaseClass();
b is BaseClass       = True
b is ChildClass      = False
b is GrandChildClass = False

BaseClass b = new ChildClass();
b is BaseClass       = True
b is ChildClass      = True
b is GrandChildClass = False

BaseClass b = new GrandChildClass();
b is BaseClass       = True
b is ChildClass      = True
b is GrandChildClass = True

typeof

型を厳密にチェックしたい場合は、typeof を使います。

using System;

// 基底クラス
class BaseClass { }
// 派生クラス
class ChildClass : BaseClass { }
// 派生クラスの派生クラス
class GrandChildClass : ChildClass { }

// メインプログラム
class Program
{
    public static void Main()
    {
        BaseClass b = new BaseClass();
        Console.WriteLine("BaseClass b = new BaseClass();");
        Console.WriteLine($"bはBaseClass型?       = {b.GetType() == typeof(BaseClass)}");
        Console.WriteLine($"bはChildClass型?      = {b.GetType() == typeof(ChildClass)}");
        Console.WriteLine($"bはGrandChildClass型? = {b.GetType() == typeof(GrandChildClass)}");

        b = new ChildClass();
        Console.WriteLine("\nBaseClass b = new ChildClass();");
        Console.WriteLine($"bはBaseClass型?       = {b.GetType() == typeof(BaseClass)}");
        Console.WriteLine($"bはChildClass型?      = {b.GetType() == typeof(ChildClass)}");
        Console.WriteLine($"bはGrandChildClass型? = {b.GetType() == typeof(GrandChildClass)}");

        b = new GrandChildClass();
        Console.WriteLine("\nBaseClass b = new GrandChildClass();");
        Console.WriteLine($"bはBaseClass型?       = {b.GetType() == typeof(BaseClass)}");
        Console.WriteLine($"bはChildClass型?      = {b.GetType() == typeof(ChildClass)}");
        Console.WriteLine($"bはGrandChildClass型? = {b.GetType() == typeof(GrandChildClass)}");
    }
}
BaseClass b = new BaseClass();
bはBaseClass型?       = True
bはChildClass型?      = False
bはGrandChildClass型? = False

BaseClass b = new ChildClass();
bはBaseClass型?       = False
bはChildClass型?      = True
bはGrandChildClass型? = False

BaseClass b = new GrandChildClass();
bはBaseClass型?       = False
bはChildClass型?      = False
bはGrandChildClass型? = True

C# プログラミング講座に戻る

コメント

タイトルとURLをコピーしました