キャストと型変換 (C# プログラミング ガイド)

C# はコンパイル時に静的に型指定されるため、変数を宣言した後、その型が変数の型に暗黙的に変換可能でない限り、変数を再び宣言したり、別の型の値を代入したりすることはできません。 たとえば、stringint に暗黙的に変換することはできません。 そのため、次のコードに示すように、iint として宣言した後、"Hello" という文字列を代入することはできません。

int i;

// error CS0029: can't implicitly convert type 'string' to 'int'
i = "Hello";

しかし場合によっては、別の型の変数やメソッドのパラメーターに値をコピーする必要が生じることもあります。 たとえば、パラメーターが double として型指定されたメソッドに、整数の変数を渡す必要が生じることもあるでしょう。 また、クラス変数をインターフェイス型の変数に代入しなければならない場合もあるかもしれません。 この種の操作は、型変換と呼ばれます。 C# では、次のような変換を実行できます。

  • 暗黙的な変換: この変換は常に成功し、データは失われないため、特別な構文は必要ありません。 例としては、小さい整数型から大きい整数型への変換や、派生クラスから基底クラスへの変換が挙げられます。

  • 明示的な変換 (キャスト) : 明示的な変換には、キャスト式が必要です。 変換時に情報が失われる可能性がある場合や、その他の理由によって変換が成功しない可能性がある場合には、キャストが必要です。 典型的な例としては、より精度の低い型 (または、より範囲が狭い型) に数値を変換する場合や、基底クラスのインスタンスを派生クラスに変換する場合が挙げられます。

  • ユーザー定義の変換: ユーザー定義の変換では、基本クラスと派生クラスという関係がないカスタム型間の明示的および暗黙的な変換を可能にするために定義できる特別なメソッドを使用します。 詳細については、「ユーザー定義の変換演算子」 に関するページを参照してください。

  • ヘルパー クラスを使用する変換: 整数と System.DateTime オブジェクトの間、16 進文字列とバイト配列の間など、互換性のない型の間で変換を行うには、System.BitConverter クラス、System.Convert クラス、および組み込み数値型の Parse メソッド (Int32.Parse など) を使用できます。 詳細については、「バイト配列を int に変換する方法」、「文字列を数値に変換する方法」、および「16 進文字列と数値型の間で変換する方法」を参照してください。

暗黙の変換

組み込みの数値型の場合、格納される値を切り捨てたり丸めたりしなくても変数に収めることができるのであれば、暗黙的な変換を実行できます。 整数型の場合、これは、ソースの型の範囲が、ターゲットの型の範囲の適切なサブセットであるという意味です。 たとえば、long 型の変数 (64 ビットの整数) は、int (32 ビットの整数) が格納できる任意の値を格納できます。 次の例の場合、コンパイラは右側の num の値を bigNum に代入する前に、この値を long 型へと暗黙的に変換します。

// Implicit conversion. A long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;

すべての暗黙的な数値変換の完全なリストについては、組み込みの数値変換に関する記事の「暗黙的な数値変換」セクションを参照してください。

参照型の場合は、特定のクラスから、その直接または間接的な基底クラスやインターフェイスに対して、常に暗黙的な変換が存在します。 派生クラスには常に基底クラスのすべてのメンバーが含まれるため、特別な構文は必要ありません。

Derived d = new Derived();

// Always OK.
Base b = d;

明示的な変換

ただし、情報が失われるリスクなしに変換を実行できない場合、コンパイラによって、明示的な変換を実行するように要求されます。これは "キャスト" と呼ばれます。 キャストとは、自分に変換を行う意図があることと、またデータが損失するか、または実行時にキャストが失敗する可能性があることを自分が認識していることをコンパイラに明示的に通知するための方法です。 キャストを実行するには、変換する値または変数の前に、キャスト先の型をかっこで囲んで指定します。 次のプログラでは、doubleint にキャストしています。このプログラムは、キャストなしではコンパイルされません。

class Test
{
    static void Main()
    {
        double x = 1234.7;
        int a;
        // Cast double to int.
        a = (int)x;
        System.Console.WriteLine(a);
    }
}
// Output: 1234

サポートされる明示的な数値変換の完全なリストについては、組み込みの数値変換に関する記事の「明示的な数値変換」セクションを参照してください。

参照型の場合は、基本型から派生型に変換する必要がある場合に、明示的なキャストが必要です。

// Create a new derived type.
Giraffe g = new Giraffe();

// Implicit conversion to base type is safe.
Animal a = g;

// Explicit conversion is required to cast back
// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe)a;

参照型の間でキャスト操作を行っても、基になるオブジェクトの実行時の型は変更されません。そのオブジェクトへの参照として使用される値の型が変更されるだけです。 詳細については、「ポリモーフィズム」を参照してください。

実行時に発生する型変換の例外

一部の参照型変換では、キャストが有効化どうかをコンパイラで判断することができません。 正しくコンパイルされたキャスト操作が実行時に失敗する可能性があります。 次の例に示すように、型キャストが実行時に失敗すると、InvalidCastException がスローされます。

class Animal
{
    public void Eat() => System.Console.WriteLine("Eating.");

    public override string ToString() => "I am an animal.";
}

class Reptile : Animal { }
class Mammal : Animal { }

class UnSafeCast
{
    static void Main()
    {
        Test(new Mammal());

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }

    static void Test(Animal a)
    {
        // System.InvalidCastException at run time
        // Unable to cast object of type 'Mammal' to type 'Reptile'
        Reptile r = (Reptile)a;
    }
}

Test メソッドには Animal パラメーターがあるため、引数 aReptile に明示的にキャストすると、物騒な想定が行われます。 思い込まずに、型を確認する方が安全です。 C# では、キャストの実行前に互換性をテストできるよう、is 演算子が提供されています。 詳細については、「パターン マッチング、is 演算子、as 演算子を使用して安全にキャストする方法」を参照してください。

C# 言語仕様

詳細については、C# 言語仕様変換に関するセクションを参照してください。

関連項目