DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

ある型の値を別の型に変換(キャスト)する

注意:ここではキャストによる型変換について説明します。ここで説明していない変換については、以下のページをご覧ください。

キャスト

ある型の値を別の型に変換する必要があるというケースはよくあります。例えば、Int32型(VB.NETではInteger、C#ではint)の変数にInt64型(VB.NETではLong、C#ではlong)の値を代入したい場合や、Object型の変数に格納された値を適当な型に変換したい場合などです。このような場合は、キャストにより型の変換を行います。

キャストは、VB.NETではCType関数で、C#ではキャスト演算子()で行うことができます。

VB.NETでは、Option StrictステートメントをOnにしない限り暗黙的な型変換が行われるため、意識してキャストを行う必要がありません。しかしほとんどの場合、明示的なキャストを行った方がパフォーマンスが向上し、間違いも起きにくくなりますので、Option StrictはOnにすべきでしょう。

以下に、Int64型をInt32型に(VB.NETではLong型をInteger型に、C#ではlong型をint型に)変換する例を示します。

VB.NET
コードを隠すコードを選択
Dim l As Long = 100
'Long型をInteger型に変換する 
Dim i As Integer = CType(l, Integer)

'VB.NETでは次のように型変換関数を使うこともできる
'Dim i As Integer = CInt(l)
C#
コードを隠すコードを選択
long l = 100;
//long型をint型に変換する
int i = (int)l;

暗黙の型変換と明示的な型変換、拡大変換と縮小変換

実は、明示的にキャストを行わなくても暗黙で型変換が行われるケースがあります。これは、「拡大変換」と呼ばれる変換が行われるケースです。拡大変換とは、型変換を行っても変換基のデータが少しも損なわれること無く、完全に変換先の型に変換できるということです。

例えば、Int32型(VB.NETではInteger、C#ではint)の値をInt64型(VB.NETではLong、C#ではlong)に変換する場合は、Int64型の方がInt32型よりも範囲が広く、Int32型で表現できる全ての数値をInt64型で表現できるため、拡大変換となります。

また、派生クラス型をそのクラスの基本型に変換する場合も、派生クラスには基本クラスのすべてのメンバが含まれているため、拡大変換となります。

以下に暗黙の型変換が行われる例を示します。

VB.NET
コードを隠すコードを選択
'Integer型をLong型に変換 
Dim i As Integer = 10
Dim l As Long = i

'TextBox型をControl型に変換 
Dim c As System.Windows.Forms.Control = New System.Windows.Forms.TextBox()
C#
コードを隠すコードを選択
//int型をlong型に変換
int i = 10;
long l = i;

//TextBox型をControl型に変換
System.Windows.Forms.Control c = new System.Windows.Forms.TextBox();

拡大変換以外の変換は、縮小変換となり、キャストによる明示的な型変換が必要です。キャストを使用せずに縮小変換をしようとすると、コンパイル時に
「エラー CS0266: 型 'float' を 'int' に暗黙的に変換できません。明示的な変換が存在します。(cast が不足していないかどうかを確認してください)」
のようなエラーが発生します。

縮小変換では、変換前のデータが失われる可能性があります。または、OverflowExceptionなどの例外がスローされる可能性があります。

補足:拡大変換でも、例えばInt32などの整数型からSingleやDoubleへの変換では、桁数は失われませんが、精度が失われる可能性があります。

以下にSingle型からInt32型に変換する例を示します。このように、小数点以下が失われます。

VB.NET
コードを隠すコードを選択
'Single型をInteger型に変換 
Dim f As Single = 1.5F
Dim i As Integer = CType(f, Integer)
'"2"と表示される 
Console.WriteLine(i)
C#
コードを隠すコードを選択
//float型をint型に変換
float f = 1.5f;
int i = (int)f;
//"1"と表示される
Console.WriteLine(i);
補足:この例のように、VB.NETのCType関数とC#のキャスト演算子とでは、結果が異なる場合があります。Single型からInt32型に変換する場合、CType関数では小数点以下を銀行型丸め(近似値の整数に丸め、0.5の場合は近似値の偶数になるように丸める)によって取り除きますが、C#では切り捨てます。Convertクラスによる変換でも、銀行型丸めとなります。

どのような変換が拡大変換で、どのような変換が縮小変換かの詳細は、MSDNの以下の項をご覧ください。

縮小変換でOverflowExceptionがスローされるようにする

縮小変換で、変換先の型の最大値を超える値を変換しようとしたとき、CType関数ではOverflowExceptionがスローされますが、C#のキャスト演算子では通常例外がスローされず、間違った値を返します。

VB.NET
コードを隠すコードを選択
Dim f As Single = Single.MaxValue
'OverflowExceptionがスローされる 
Dim i As Integer = CType(f, Integer)
Console.WriteLine(i)
C#
コードを隠すコードを選択
float f = float.MaxValue;
int i = (int)f;
//"-2147483648"と表示される
Console.WriteLine(i);

C#のキャスト演算子でOverflowExceptionがスローされるようにするには、checkedキーワードを使います。

C#
コードを隠すコードを選択
float f = float.MaxValue;
//OverflowExceptionがスローされる
int i = checked((int)f);

または、/checkedコンパイラオプションを使用する方法もあります。

キャストで可能な変換

キャストでは、次のような変換が可能です。

  • 参照変換。参照しているオブジェクトが継承している型、または実装しているインターフェイスへの変換。参照変換では、参照しているオブジェクト自体が変わるわけではなく、参照で使用している変数の型が変わるだけ。
  • ボックス化変換(ボックス化とボックス化解除)。
  • 変換演算子で定義されている変換。変換演算子について詳しくは、こちら

それぞれの例を示します。

VB.NET
コードを隠すコードを選択
'参照変換 
Dim b As New System.Windows.Forms.Button()
Dim c As System.Windows.Forms.Control = CType(b, System.Windows.Forms.Control)

'ボックス化変換 
Dim i As Integer = 1
Dim obj As Object = i

'変換演算子による変換 
Dim p As System.Drawing.Point = New Point(0, 0)
Dim s As System.Drawing.Size = CType(p, System.Drawing.Size)
C#
コードを隠すコードを選択
//参照変換
System.Windows.Forms.Button b = new System.Windows.Forms.Button();
System.Windows.Forms.Control c = (System.Windows.Forms.Control)b;

//ボックス化変換
int i = 1;
object obj = i;

//変換演算子による変換
System.Drawing.Point p = new Point(0, 0);
System.Drawing.Size s = (System.Drawing.Size)p;

VB.NETのCType関数ではさらに、配列型の変換や、数値や日時などと文字列との変換も可能です。詳しくはMSDNの「Visual Basic における型変換」をご覧ください。

よりパフォーマンスの良い方法

参照変換とボックス化変換だけであれば、よりパフォーマンスの良い方法もあります。

VB.NETでは、CTypeの代わりに、DirectCastを使うことができます。DirectCastはCTypeよりもパフォーマンスに優れています。

.NET Framework 2.0からは、TryCastを使うこともできます。TryCastは変換できない場合でもエラーを出さずに、Nothingを返します。

VB.NET
コードを隠すコードを選択
'DirectCastを使って変換した例
Dim l As New System.Windows.Forms.Label()
Dim c As System.Windows.Forms.Control = _
    DirectCast(l, System.Windows.Forms.Control)

'TryCastを使って変換した例
Dim c2 As System.Windows.Forms.Control = _
    TryCast(l, System.Windows.Forms.Control)

C#では、as演算子を使うこともできます。as演算子は変換できない場合でもエラーを出さずに、nullを返します。

C#
コードを隠すコードを選択
//asを使って変換する例
System.Windows.Forms.Label l = new System.Windows.Forms.Label();
System.Windows.Forms.Control c = l as System.Windows.Forms.Control;

キャストできるか調べる

VB.NETではTypeOf...Is式で、C#ではisキーワードでキャストできるかを調べることができます。ただしこれらは変換演算子で変換できるケースを考慮しませんので、参照変換かボックス化変換ができるかしか調べることができません。

VB.NET
コードを隠すコードを選択
Dim l As New System.Windows.Forms.Label()
'Controlにキャストできるか調べる 
If TypeOf l Is System.Windows.Forms.Control Then
    'キャストする 
    Dim c As System.Windows.Forms.Control = CType(l, System.Windows.Forms.Control)
End If
C#
コードを隠すコードを選択
System.Windows.Forms.Label l = new System.Windows.Forms.Label();
//Controlにキャストできるか調べる
if (l is System.Windows.Forms.Control)
{
    //キャストする
    System.Windows.Forms.Control c = (System.Windows.Forms.Control)l;
}

先に紹介したTryCastとas演算子を使っても同様のことができます。

VB.NET
コードを隠すコードを選択
Dim l As New System.Windows.Forms.Label()
'Controlにキャストする 
Dim c As System.Windows.Forms.Control = TryCast(l, System.Windows.Forms.Control)
If c IsNot Nothing Then
    Console.WriteLine("キャストに成功しました。")
End If
C#
コードを隠すコードを選択
System.Windows.Forms.Label l = new System.Windows.Forms.Label();
//Controlにキャストする
System.Windows.Forms.Control c = l as System.Windows.Forms.Control;
if (c != null)
{
    Console.WriteLine("キャストに成功しました。");
}

その他の方法

型変換を行う方法としては他にも、Convertクラスを使う方法があります。Convertクラスの各メソッドにより、基本型間での変換を行うことができます。

VB.NETでは、データ型変換関数を使用することでも型変換が可能です。詳しくは「データ型変換関数」等をご覧ください。

  • 履歴:
  • 2010/9/29 「キャストできるか調べる」のC#のコードでisがasになっていたのを修正。
  • 2012/6/10 「キャスト」のVB.NETのコードを修正。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • .NET Tipsをご利用いただく際は、注意事項をお守りください。