注意:ここではキャストによる型変換について説明します。ここで説明していない変換については、以下のページをご覧ください。
ある型の値を別の型に変換する必要があるというケースはよくあります。例えば、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型に)変換する例を示します。
Dim l As Long = 100 'Long型をInteger型に変換する Dim i As Integer = CType(l, Integer) 'VB.NETでは次のように型変換関数を使うこともできる 'Dim i As Integer = CInt(l)
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型で表現できるため、拡大変換となります。
また、派生クラス型をそのクラスの基本型に変換する場合も、派生クラスには基本クラスのすべてのメンバが含まれているため、拡大変換となります。
以下に暗黙の型変換が行われる例を示します。
'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()
//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型に変換する例を示します。このように、小数点以下が失われます。
'Single型をInteger型に変換 Dim f As Single = 1.5F Dim i As Integer = CType(f, Integer) '"2"と表示される Console.WriteLine(i)
//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の以下の項をご覧ください。
縮小変換で、変換先の型の最大値を超える値を変換しようとしたとき、CType関数ではOverflowExceptionがスローされますが、C#のキャスト演算子では通常例外がスローされず、間違った値を返します。
Dim f As Single = Single.MaxValue 'OverflowExceptionがスローされる Dim i As Integer = CType(f, Integer) Console.WriteLine(i)
float f = float.MaxValue; int i = (int)f; //"-2147483648"と表示される Console.WriteLine(i);
C#のキャスト演算子でOverflowExceptionがスローされるようにするには、checkedキーワードを使います。
float f = float.MaxValue; //OverflowExceptionがスローされる int i = checked((int)f);
または、/checkedコンパイラオプションを使用する方法もあります。
キャストでは、次のような変換が可能です。
それぞれの例を示します。
'参照変換 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)
//参照変換 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を返します。
'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を返します。
//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キーワードでキャストできるかを調べることができます。ただしこれらは変換演算子で変換できるケースを考慮しませんので、参照変換かボックス化変換ができるかしか調べることができません。
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
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演算子を使っても同様のことができます。
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
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では、データ型変換関数を使用することでも型変換が可能です。詳しくは「データ型変換関数」等をご覧ください。
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。