C#: 型の変換
1. 暗黙の型変換
暗黙の型変換は、特別な構文を必要とせず、コンパイラによって自動的に行われます。これは、より狭い型からより広い型へ代入する際に発生し、データが失われることはありません。
(1) 変換ルール
int→longint→doublefloat→double- すべてのタイプ →
string(ToString()経由)
▶ サンプル
int a = 100;
long b = a;
int c = 42;
double d = c;
float e = 3.14f;
double f = e;
int g = 99;
string h = g.ToString();
Console.WriteLine($"int→long: {b}");
Console.WriteLine($"int→double: {d}");
Console.WriteLine($"float→double: {f}");
Console.WriteLine($"int→string: {h}");
int→long: 100
int→double: 42
float→double: 3.14
int→string: 99
2. 明示的な変換
明示的な型変換を行うには、キャスト構文を使用し、値の前にターゲット型を括弧で囲む必要があります。これは、より広い型からより狭い型へ代入する際に発生し、データが失われる可能性があります。
(1) 構文
TargetType variable = (TargetType)value;
▶ サンプル
double pi = 3.14;
int truncated = (int)pi;
int number = 42;
double widened = (double)number;
long big = 3000000000L;
int overflow = (int)big;
Console.WriteLine($"(int)3.14 → {truncated}");
Console.WriteLine($"(double)42 → {widened}");
Console.WriteLine($"(int)3000000000L → {overflow}");
(int)3.14 → 3
(double)42 → 42
(int)3000000000L → -1294967296
警告:明示的な型変換を行うと、精度の低下やオーバーフローが発生する可能性があります。型変換を行う前には、必ずデータの範囲を確認してください。
3. クラスの変換
System.Convert クラスは、さまざまな基本型間の変換を行うための静的メソッドを提供します。これは、直接の型キャストよりも安全で、表現力に富んでいます。
(1) 一般的な手法
| 方法 | 説明 |
|---|---|
Convert.ToInt32 |
int に変換 |
Convert.ToDouble |
double に変換 |
Convert.ToString |
string に変換 |
Convert.ToBoolean |
bool に変換 |
▶ サンプル
string s1 = "42";
string s2 = "3.14";
string s3 = "0";
int n1 = Convert.ToInt32(s1);
double n2 = Convert.ToDouble(s2);
string n3 = Convert.ToString(n1);
bool n4 = Convert.ToBoolean(s3);
bool n5 = Convert.ToBoolean(1);
Console.WriteLine($"ToInt32: {n1}");
Console.WriteLine($"ToDouble: {n2}");
Console.WriteLine($"ToString: {n3}");
Console.WriteLine($"ToBoolean(\"0\"): {n4}");
Console.WriteLine($"ToBoolean(1): {n5}");
ToInt32: 42
ToDouble: 3.14
ToString: 42
ToBoolean("0"): False
ToBoolean(1): True
ヒント:
Convert.ToBooleanは文字列の場合、"True"および"False"のみを認識します。数値の場合、0 以外の値はtrue、0 はfalseとなります。
4. Parse および TryParse
(1) 解析方法
Parse は、文字列を対象の型に変換し、形式が不正な場合は FormatException をスローします。
例
int a = int.Parse("42");
double b = double.Parse("3.14");
Console.WriteLine($"int.Parse: {a}");
Console.WriteLine($"double.Parse: {b}");
int.Parse: 42
double.Parse: 3.14
try
{
int bad = int.Parse("hello");
}
catch (FormatException ex)
{
Console.WriteLine($"Parse failed: {ex.Message}");
}
Parse failed: Input string was not in a correct format.
(2) TryParse メソッド
TryParse は例外を投げません。成功を示す bool を返し、解析された値を out パラメータを介して出力します。
例
if (int.TryParse("42", out int result1))
{
Console.WriteLine($"Parse succeeded: {result1}");
}
if (!int.TryParse("abc", out int result2))
{
Console.WriteLine($"Parse failed, result2 = {result2}");
}
Parse succeeded: 42
Parse failed, result2 = 0
ヒント:ユーザーデータなど信頼性の低い入力を扱う場合は、例外処理によるパフォーマンスの低下を避けるため、
TryParseを使用することをお勧めします。
5. 梱包と開梱
(1) ボクシング
ボクシングとは、値型をobject参照型に変換するプロセスです。この際、値がスタックからヒープへコピーされ、メモリの割り当てが行われます。
例
int value = 42;
object boxed = value;
Console.WriteLine($"Boxed: {boxed}, Type: {boxed.GetType()}");
Boxed: 42, Type: System.Int32
(2) 開封
アンボクシングとは、object 参照を明示的に値型にキャストするプロセスです。これには明示的なキャストが必要であり、型が一致しない場合は InvalidCastException 例外がスローされます。
例
object boxed = 42;
int unboxed = (int)boxed;
Console.WriteLine($"Unboxed: {unboxed}");
Unboxed: 42
object boxed = 42;
try
{
double wrong = (double)boxed;
}
catch (InvalidCastException ex)
{
Console.WriteLine($"Unbox type mismatch: {ex.Message}");
}
Unbox type mismatch: Specified cast is not valid.
警告:アンボクシング操作におけるターゲット型は、元のボクシング型と完全に一致している必要があります。一致しない場合、
InvalidCastException例外がスローされます。
6. 型変換におけるよくある落とし穴
(1) 浮動小数点数から整数への変換に伴う精度の低下
double d = 9.99;
int i = (int)d;
Console.WriteLine($"9.99 → {i}");
9.99 → 9
(2) ワイド型からナロー型へのオーバーフロー
long big = 5000000000L;
int small = (int)big;
Console.WriteLine($"5000000000L → {small}");
5000000000L → 705032704
(3) 無効な文字列に対するParseThrowingの発生
try
{
int n = int.Parse("3.14");
}
catch (FormatException)
{
Console.WriteLine("Cannot parse \"3.14\" as int");
}
Cannot parse "3.14" as int
ヒント - 落とし穴を避けるためのベストプラクティス:変換前にデータの範囲を確認すること;
TryParseを優先して使用すること;オーバーフローが発生する可能性がある場合は、checkedキーワードを使用すること。
❓ よくある質問
📖 まとめ
- 暗黙の型変換は、より狭い型からより広い型へと行われ、安全かつ自動的に行われます
- 明示的な型変換ではキャスト構文が使用され、精度が低下したり、オーバーフローが発生したりする可能性があります
- Convert クラスは、型をまたぐ安全な変換メソッドを提供します
- Parse は文字列を直接解析し、失敗した場合は例外をスローします。一方、TryParse は安全にブール値を返します。
- ボクシングでは、値型がヒープ上に割り当てられたオブジェクトとしてラップされます。アンボクシングを行うには、型が完全に一致している必要があります。
- 例外や暗黙のボクシングを避けるため、本番コードでは TryParse を使用することを推奨します
📝 練習問題
shortの値 32767 をintに暗黙的に変換し、intの値 32768 をshortに明示的にキャストするプログラムを作成し、その結果を確認してください。Convert.ToInt32を使用して 2.5 と 3.5 を変換し、バンカーの丸め処理の挙動を確認する- 文字列パラメータを受け取り、
TryParseを使用してそれを安全にintとして解析し、成功した場合は解析された値を返し、失敗した場合は -1 を返すメソッドを作成してください。 - ボクシングとアンボクシングを実演するコードを記述し、意図的に間違った型でアンボクシングを行い、
InvalidCastExceptionをキャッチする - オーバーフローを起こした
intのキャストをcheckedキーワードで囲み、OverflowExceptionがスローされるかどうかを確認する