暗黙的・明示的な型変換
暗黙の型変換
もっとも基本的な型変換に、代入時の暗黙の型変換があります。 例えばshort→intやint→doubleなど、データの欠損や桁落ち、オーバーフローが発生しない拡大変換(widening conversion)となる場合には、暗黙の型変換を行うことができます。
using System;
class Sample {
static void Main()
{
int i = 42;
double d;
d = i; // intからdoubleへの暗黙の型変換が行われる
Console.WriteLine(i);
Console.WriteLine(d);
}
}
Option Strict On
Imports System
Class Sample
Shared Sub Main()
Dim i As Integer = 42
Dim d As Double
d = i ' IntegerからDoubleへの暗黙の型変換が行われる
Console.WriteLine(i)
Console.WriteLine(d)
End Sub
End Class
42 42
明示的な型変換 (キャスト)
逆に、int→shortやdouble→intなど、データの欠損や桁落ち、オーバーフローが発生し得る縮小変換(narrowing conversion)なる場合には、暗黙の型変換を行うことはできません。
using System;
class Sample {
static void Main()
{
double d = 3.14;
int i;
i = d; // doubleからintへの縮小変換となるので暗黙の型変換はできない
// error CS0266: 型 'double' を 'int' に暗黙的に変換できません。明示的な変換が存在します。(cast が不足していないかどうかを確認してください)
}
}
Option Strict On
Imports System
Class Sample
Shared Sub Main()
Dim d As Double = 3.14
Dim i As Integer
i = d ' DoubleからIntegerへの縮小変換となるので暗黙の型変換はできない
' error BC30512: Option Strict On で 'Double' から 'Integer' への暗黙的な変換はできません。
End Sub
End Class
この場合、キャスト構文やCIntなどの型変換関数を使って明示的な型変換を行う必要があります。
using System;
class Sample {
static void Main()
{
double d = 3.14;
int i;
i = (int)d; // doubleからintへのキャスト
Console.WriteLine(d);
Console.WriteLine(i);
}
}
Option Strict On
Imports System
Class Sample
Shared Sub Main()
Dim d As Double = 3.14
Dim i As Integer
i = CInt(d) ' DoubleからIntegerへの型変換
Console.WriteLine(d)
Console.WriteLine(i)
End Sub
End Class
3.14 3
どのような場合に拡大変換または縮小変換となるかは、以下のドキュメントでまとめられています。
オーバーフローのチェック
C#では、checked/uncheckedステートメントを使うことで整数型へのキャストの際にオーバーフローのチェックを行うかどうかを制御することができます。 checkedステートメントを使うと例外OverflowExceptionをスローするようにすることができ、uncheckedステートメントを使うとオーバーフローのチェックを行わないようにすることができます。 この点についてより詳しくは整数型のオーバーフローとチェックで解説しています。
using System;
class Sample {
static void Main()
{
double d = double.MaxValue;
int i;
// デフォルトの動作で
// キャストする
i = (int)d;
Console.WriteLine(i);
}
}
-2147483648
using System;
class Sample {
static void Main()
{
double d = double.MaxValue;
int i;
// オーバーフローのチェックを
// 行わずにキャストする
i = unchecked((int)d);
Console.WriteLine(i);
}
}
-2147483648
using System;
class Sample {
static void Main()
{
double d = double.MaxValue;
int i;
// オーバーフローのチェックを
// 行った上でキャストする
i = checked((int)d);
Console.WriteLine(i);
}
}
ハンドルされていない例外: System.OverflowException: 算術演算の結果オーバーフローが発生しました。 場所 Sample.Main()
実数型から整数型への変換 (Round, Ceiling, Floor)
float(Single)、doubleおよびdecimalから整数型へ変換する際に、Math.Round、Math.Ceiling、Math.Floorといった端数処理のメソッドと組み合わせて変換することが出来ます。 これらのメソッドの動作と使い方については数学関数 §.実数の丸め・端数処理 (Truncate, Ceiling, Floor, Round)で詳しく解説しています。
文字列への/からの変換
文字列への変換 (ToString)
基本型から文字列への変換にはToStringメソッドを使うことが出来ます。 単純な文字列化の他、書式を指定した変換も出来ます。
using System;
class Sample {
static void Main()
{
int i = 42;
double d = 3.141592;
string s1 = i.ToString();
string s2 = i.ToString("D8");
string s3 = d.ToString();
string s4 = d.ToString("F4");
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.WriteLine(s3);
Console.WriteLine(s4);
}
}
Imports System
Class Sample
Shared Sub Main()
Dim i As Integer = 42
Dim d As Double = 3.141592
Dim s1 As String = i.ToString()
Dim s2 As String = i.ToString("D8")
Dim s3 As String = d.ToString()
Dim s4 As String = d.ToString("F4")
Console.WriteLine(s1)
Console.WriteLine(s2)
Console.WriteLine(s3)
Console.WriteLine(s4)
End Sub
End Class
42 00000042 3.141592 3.1416
ToStringメソッドの引数に"D8"
や"F4"
などの書式指定文字列を指定することで桁数や数値の表記を指定して文字列化することができます。 ToStringメソッドに指定できる書式については、書式指定子で詳しく解説しています。
2進・10進・16進などの形式での文字列化については、ビット演算 §.基数を指定した数値から文字列への変換を参照してください。
文字列からの変換 (Parse, TryParse)
文字列から基本型への変換にはInt32.Parse、Double.ParseなどのParseメソッドを使うことが出来ます。
using System;
class Sample {
static void Main()
{
int i1 = int.Parse("42");
int i2 = int.Parse("000042");
double d1 = double.Parse("3.14");
double d2 = double.Parse("1.23E+3");
Console.WriteLine(i1);
Console.WriteLine(i2);
Console.WriteLine(d1);
Console.WriteLine(d2);
}
}
Imports System
Class Sample
Shared Sub Main()
Dim i1 As Integer = Integer.Parse("42")
Dim i2 As Integer = Integer.Parse("000042")
Dim d1 As Double = Double.Parse("3.14")
Dim d2 As Double = Double.Parse("1.23E+3")
Console.WriteLine(i1)
Console.WriteLine(i2)
Console.WriteLine(d1)
Console.WriteLine(d2)
End Sub
End Class
42 42 3.14 1230
このメソッドでは、変換できない形式の場合はFormatException、変換した値が型の最大値・最小値を超える場合はOverflowExceptionがスローされます。
変換時に例外をスローさせたくない場合は、Int32.TryParse、Double.TryParseなどのTryParseメソッドを使うことが出来ます。 このメソッドは、変換できた場合はtrue、変換できなかった場合はfalseを返し、変換した値は2番目の引数(out/ByRef)に代入されます。
using System;
class Sample {
static void Main()
{
int i;
if (int.TryParse("42", out i))
Console.WriteLine(i);
else
Console.WriteLine("変換できない値");
if (int.TryParse("abc", out i))
Console.WriteLine(i);
else
Console.WriteLine("変換できない値");
if (int.TryParse("01234567890123456789", out i))
Console.WriteLine(i);
else
Console.WriteLine("変換できない値");
double d;
if (double.TryParse("3.14", out d))
Console.WriteLine(d);
else
Console.WriteLine("変換できない値");
if (double.TryParse("1.2345E+6789", out d))
Console.WriteLine(d);
else
Console.WriteLine("変換できない値");
}
}
Imports System
Class Sample
Shared Sub Main()
Dim i As Integer
If Integer.TryParse("42", i) Then
Console.WriteLine(i)
Else
Console.WriteLine("変換できない値")
End If
If Integer.TryParse("abc", i) Then
Console.WriteLine(i)
Else
Console.WriteLine("変換できない値")
End If
If Integer.TryParse("01234567890123456789", i) Then
Console.WriteLine(i)
Else
Console.WriteLine("変換できない値")
End If
Dim d As Double
If Double.TryParse("3.14", d) Then
Console.WriteLine(d)
Else
Console.WriteLine("変換できない値")
End If
If Double.TryParse("1.2345E+6789", d) Then
Console.WriteLine(d)
Else
Console.WriteLine("変換できない値")
End If
End Sub
End Class
42 変換できない値 変換できない値 3.14 変換できない値
日付型(DateTime/DateTimeOffset)とParse・TryParseメソッドについては日時・文字列の変換と書式で詳しく解説しています。
基数を指定した変換 (Convert.ToXXX)
16進・8進・2進数形式の文字列から整数型/整数型から文字列に変換するには、Convert.ToStringメソッドおよびConvert.ToInt32などのメソッドを使うことができます。 このメソッドでは、基数として2、8、10、16のいずれかを指定することができます。 これ以外の基数を指定すると例外ArgumentExceptionがスローされます。
このメソッドでは、符号付きの数値が許可されるかどうかなどの動作が基数によって変わります。 メソッドの詳しい動作についてはビット演算 §.基数を指定した文字列から数値への変換を参照してください。
以下は、基数を指定して文字列と整数型の値を変換する例です。
using System;
class Sample {
static void Main()
{
// 数値128を文字列に変換
Console.WriteLine(Convert.ToString(128, 2)); // 2進数に変換
Console.WriteLine(Convert.ToString(128, 8)); // 8進数に変換
Console.WriteLine(Convert.ToString(128, 10)); // 10進数に変換
Console.WriteLine(Convert.ToString(128, 16)); // 16進数に変換
Console.WriteLine();
// 文字列"100"を数値に変換
Console.WriteLine(Convert.ToInt32("100", 2)); // 2進数として変換
Console.WriteLine(Convert.ToInt32("100", 8)); // 8進数として変換
Console.WriteLine(Convert.ToInt32("100", 10)); // 10進数として変換
Console.WriteLine(Convert.ToInt32("100", 16)); // 16進数として変換
}
}
Imports System
Class Sample
Shared Sub Main()
' 数値128を文字列に変換
Console.WriteLine(Convert.ToString(128, 2)) ' 2進数に変換
Console.WriteLine(Convert.ToString(128, 8)) ' 8進数に変換
Console.WriteLine(Convert.ToString(128, 10)) ' 10進数に変換
Console.WriteLine(Convert.ToString(128, 16)) ' 16進数に変換
Console.WriteLine()
' 文字列"100"を数値に変換
Console.WriteLine(Convert.ToInt32("100", 2)) ' 2進数として変換
Console.WriteLine(Convert.ToInt32("100", 8)) ' 8進数として変換
Console.WriteLine(Convert.ToInt32("100", 10)) ' 10進数として変換
Console.WriteLine(Convert.ToInt32("100", 16)) ' 16進数として変換
End Sub
End Class
10000000 200 128 80 4 64 100 256
バイト配列への/からの変換
基本型とバイト配列への/からの変換
BitConverter.GetBytesメソッドを用いると、基本型をバイト配列に変換することが出来ます。 逆にBitConverter.ToXXXメソッドを用いると、バイト配列から基本型に変換することが出来ます。 StreamクラスやBinaryReaderクラス・BinaryWriterクラスを使ってバイナリデータを扱う場合などにこれらのメソッドが役立ちます。
ToXXXメソッドでは、変換するバイト配列と、変換する最初のインデックスを指定する必要があります。 なお、BitConverter.ToStringメソッドは、各バイトをハイフンで連結した文字列を返します。
using System;
class Sample {
static void Main()
{
byte[] bytes = new byte[] {0xff, 0xff, 0x80, 0x00};
Console.WriteLine(BitConverter.ToString(bytes, 0));
Console.WriteLine("{0} 0x{0:X8}", BitConverter.ToInt32(bytes, 0));
Console.WriteLine("{0} 0x{0:X4}", BitConverter.ToInt16(bytes, 0));
Console.WriteLine("{0} 0x{0:X4}", BitConverter.ToInt16(bytes, 2));
Console.WriteLine(BitConverter.ToSingle(bytes, 0));
Console.WriteLine();
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(42)));
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(1.0e+5)));
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(double.PositiveInfinity)));
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes('あ')));
}
}
Imports System
Class Sample
Shared Sub Main()
Dim bytes() As Byte = New byte() {&hFF, &hFF, &h80, &h00}
Console.WriteLine(BitConverter.ToString(bytes, 0))
Console.WriteLine("{0} 0x{0:X8}", BitConverter.ToInt32(bytes, 0))
Console.WriteLine("{0} 0x{0:X4}", BitConverter.ToInt16(bytes, 0))
Console.WriteLine("{0} 0x{0:X4}", BitConverter.ToInt16(bytes, 2))
Console.WriteLine(BitConverter.ToSingle(bytes, 0))
Console.WriteLine()
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(42)))
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(1.0e+5)))
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(double.PositiveInfinity)))
Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes("あ"c)))
End Sub
End Class
FF-FF-80-00 8454143 0x0080FFFF -1 0xFFFF 128 0x0080 1.184678E-38 2A-00-00-00 00-00-00-00-00-6A-F8-40 00-00-00-00-00-00-F0-7F 42-30
ただし、BitConverter.ToStringの逆の動作をするメソッド、つまりBitConverter.ToStringの出力形式と同じ文字列からバイト配列を取得するメソッドは存在しないため、自分で実装する必要があります。 また、この形式の文字列から基本型に直接変換するメソッドも用意されていないため、これも自分で実装する必要があります。
using System;
class Sample {
static byte[] ToByteArray(string data)
{
// ハイフン '-' で分割
string[] byteStrings = data.Split('-');
// 配列に分割した文字列をバイト配列に変換
return Array.ConvertAll(byteStrings, delegate(string s) {
return Convert.ToByte(s, 16); // 16進形式の文字列からByteに変換
});
}
static void Main()
{
string data = "FF-FF-80-00";
Console.WriteLine("{0} => {1} 0x{1:X8}", data, BitConverter.ToInt32(ToByteArray(data), 0));
data = "00-00-00-00-00-6A-F8-40";
Console.WriteLine("{0} => {1}", data, BitConverter.ToDouble(ToByteArray(data), 0));
}
}
Imports System
Class Sample
Shared Function ToByteArray(ByVal data As String) As Byte()
' ハイフン '-' で分割
Dim byteStrings As String() = data.Split("-"c)
' 配列に分割した文字列をバイト配列に変換
Return Array.ConvertAll(Of String, Byte)(byteStrings, AddressOf ToByteFromHex)
End Function
Shared Function ToByteFromHex(ByVal hex As String) As Byte
' 16進形式の文字列からByteに変換
Return Convert.ToByte(hex, 16)
End Function
Shared Sub Main()
Dim data As String = "FF-FF-80-00"
Console.WriteLine("{0} => {1} 0x{1:X8}", data, BitConverter.ToInt32(ToByteArray(data), 0))
data = "00-00-00-00-00-6A-F8-40"
Console.WriteLine("{0} => {1}", data, BitConverter.ToDouble(ToByteArray(data), 0))
End Sub
End Class
FF-FF-80-00 => 8454143 0x0080FFFF 00-00-00-00-00-6A-F8-40 => 100000
リファレンスでは明記されていませんが、結果として得られるバイト表現や変換結果は実行している環境のエンディアンなどにより変わると思われます。 現在実行している環境のエンディアンを調べるには、BitConverter.IsLittleEndianプロパティを参照します(ランタイム・システム・プラットフォームの情報 §.エンディアン)。 また、IPAddressクラスのNetworkToHostOrderメソッドを使うことで整数型の値をネットワークバイトオーダー(ビッグエンディアン)からホストバイトオーダーに、HostToNetworkOrderメソッドを使うことでホストバイトオーダーからネットワークバイトオーダーに変換することが出来ます。
using System;
using System.Net;
class Sample {
static void Main()
{
Console.WriteLine("IsLittleEndian: {0}", BitConverter.IsLittleEndian);
Console.WriteLine("NetworkToHostOrder");
Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.NetworkToHostOrder(16));
Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.NetworkToHostOrder(-256));
Console.WriteLine("HostToNetworkOrder");
Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.HostToNetworkOrder(16));
Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.HostToNetworkOrder(-256));
}
}
Imports System
Imports System.Net
Class Sample
Shared Sub Main()
Console.WriteLine("IsLittleEndian: {0}", BitConverter.IsLittleEndian)
Console.WriteLine("NetworkToHostOrder")
Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.NetworkToHostOrder(16))
Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.NetworkToHostOrder(-256))
Console.WriteLine("HostToNetworkOrder")
Console.WriteLine("{0:X8} => {1:X8}", 16, IPAddress.HostToNetworkOrder(16))
Console.WriteLine("{0:X8} => {1:X8}", -256, IPAddress.HostToNetworkOrder(-256))
End Sub
End Class
IsLittleEndian: True NetworkToHostOrder 00000010 => 10000000 FFFFFF00 => 00FFFFFF HostToNetworkOrder 00000010 => 10000000 FFFFFF00 => 00FFFFFF
BitConverterクラスのメソッドを使うことで基本型とバイト配列の相互変換を行うことができますが、独自に定義した構造体などの変換には対応していません。 構造体とバイト配列との相互変換についてはBinaryReader・BinaryWriterでの構造体の読み書きで解説しています。
このほかバイト配列に関する操作についてバイト列操作でも解説しています。
文字列とバイト配列への/からの変換
Encodingクラスを使うことで、任意の文字コードを用いて文字列とバイト配列の変換を行うことが出来ます。 GetBytesメソッドで文字列からバイト配列、GetStringメソッドでバイト配列から文字列に変換できます。
using System;
using System.Text;
class Sample {
static void Main()
{
Console.WriteLine(BitConverter.ToString(Encoding.ASCII.GetBytes("ABC")));
Console.WriteLine(BitConverter.ToString(Encoding.UTF8.GetBytes("あいう")));
Console.WriteLine(BitConverter.ToString(Encoding.GetEncoding(932).GetBytes("漢字")));
Console.WriteLine(Encoding.ASCII.GetString(new byte[] {0x41, 0x42, 0x43}));
Console.WriteLine(Encoding.UTF8.GetString(new byte[] {0xE3, 0x81, 0x82, 0xE3, 0x81, 0x84, 0xE3, 0x81, 0x86}));
Console.WriteLine(Encoding.GetEncoding(932).GetString(new byte[] {0x8A, 0xBF, 0x8E, 0x9A}));
}
}
Imports System
Imports System.Text
Class Sample
Shared Sub Main()
Console.WriteLine(BitConverter.ToString(Encoding.ASCII.GetBytes("ABC")))
Console.WriteLine(BitConverter.ToString(Encoding.UTF8.GetBytes("あいう")))
Console.WriteLine(BitConverter.ToString(Encoding.GetEncoding(932).GetBytes("漢字")))
Console.WriteLine(Encoding.ASCII.GetString(New Byte() {&h41, &h42, &h43}))
Console.WriteLine(Encoding.UTF8.GetString(New Byte() {&hE3, &h81, &h82, &hE3, &h81, &h84, &hE3, &h81, &h86}))
Console.WriteLine(Encoding.GetEncoding(932).GetString(New Byte() {&h8A, &hBF, &h8E, &h9A}))
End Sub
End Class
41-42-43 E3-81-82-E3-81-84-E3-81-86 8A-BF-8E-9A ABC あいう 漢字
基本型間の変換
Convertクラス
Convertクラスには、基本型間の変換を行うメソッドが用意されています。 これらのメソッドによる変換の結果は、キャストによる変換や、基本型のParseメソッドやToStringメソッドを直接呼び出す場合と概ね同じであるため、直接使う機会はあまりありません。 実数型から整数型への変換では、最近接偶数への丸め(MidpointRounding.ToEven)が行われます。
メソッド | 動作 |
---|---|
ToByte | 文字列からByteへの変換 |
ToChar | 文字列からCharへの変換 |
ToInt16 | 文字列からInt16への変換 |
ToInt32 | 文字列からInt32への変換 |
ToInt64 | 文字列からInt64への変換 |
ToSByte | 文字列からSByteへの変換 |
ToUInt16 | 文字列からUInt16への変換 |
ToUInt32 | 文字列からUInt23への変換 |
ToUInt64 | 文字列からUInt64への変換 |
ToSingle | 文字列からSingleへの変換 |
ToDouble | 文字列からDoubleへの変換 |
ToDecimal | 文字列からDecimalへの変換 |
ToBoolean | 文字列からBooleanへの変換 |
ToDateTime | 文字列からDateTimeへの変換 |
ToString | 文字列からStringへの変換 |
このメソッドは、変換できない形式の場合はFormatException、変換した値が型の最大値・最小値を超える場合はOverflowException、変換が定義されていない場合(DateTimeからInt32など)はInvalidCastExceptionをスローします。
また、Convertクラスにはobjectから任意の型に変換するChangeTypeメソッドも用意されています。 このメソッドは変換後の型をTypeクラスまたはTypeCode列挙型で指定することが出来ます。 変換される型はIConvertibleインターフェイスを実装している必要があります(詳しくはユーザ定義の型変換で解説します)。 当然、変換できない型の場合には例外InvalidCastExceptionがスローされます。
以下の例は、Convertクラスのメソッドを使って基本型の型変換を行ったものです。
using System;
class Sample {
static void Main()
{
int i1 = Convert.ToInt32(3.5);
int i2 = Convert.ToInt32(4.5);
Console.WriteLine(i1);
Console.WriteLine(i2);
double d = Convert.ToDouble(16);
Console.WriteLine(d);
object o1 = Convert.ChangeType("3.14", typeof(double));
object o2 = Convert.ChangeType("3.14", TypeCode.Double);
object o3 = Convert.ChangeType("72", typeof(int));
object o4 = Convert.ChangeType("72", TypeCode.Int32);
Console.WriteLine("{0} ({1})", o1, o1.GetType());
Console.WriteLine("{0} ({1})", o2, o2.GetType());
Console.WriteLine("{0} ({1})", o3, o3.GetType());
Console.WriteLine("{0} ({1})", o4, o4.GetType());
}
}
Imports System
Class Sample
Shared Sub Main()
Dim i1 As Integer = Convert.ToInt32(3.5)
Dim i2 As Integer = Convert.ToInt32(4.5)
Console.WriteLine(i1)
Console.WriteLine(i2)
Dim d As Double = Convert.ToDouble(16)
Console.WriteLine(d)
Dim o1 As Object = Convert.ChangeType("3.14", GetType(Double))
Dim o2 As Object = Convert.ChangeType("3.14", TypeCode.Double)
Dim o3 As Object = Convert.ChangeType("72", GetType(Integer))
Dim o4 As Object = Convert.ChangeType("72", TypeCode.Int32)
Console.WriteLine("{0} ({1})", o1, o1.GetType())
Console.WriteLine("{0} ({1})", o2, o2.GetType())
Console.WriteLine("{0} ({1})", o3, o3.GetType())
Console.WriteLine("{0} ({1})", o4, o4.GetType())
End Sub
End Class
4 4 16 3.14 (System.Double) 3.14 (System.Double) 72 (System.Int32) 72 (System.Int32)
XmlConvertクラス
XmlConvertクラスは本来、XMLスキーマのデータ型との変換を行うために用意されてるものですが、ConvertクラスではサポートされていないGuid、TimeSpan、DateTimeOffsetと文字列との変換を行うことが出来ます。