🥊

【C#】int → objectの裏側、ボクシング,アンボクシングとは【色々試してみた】

に公開

ボクシングとは

  • 値型 → 参照型 への変換で暗黙的に発生する処理
  • ヒープ割り当て + GC対象コピー発生のため、パフォーマンスの観点で望ましくない
int i = 10;
object o = i; //iの値がヒープにコピーされ、object参照が生成される

アンボクシングとは

  • 参照型 → 値型への変換で発生する処理
  • 明示的キャストを必要とする
  • 失敗した場合は実行時に例外が発生する
object o = 10;
int i = (int)o;

アンボクシングで例外が起きる例

OK

object o = "hello";
string s = (string)o;

NG (InvalidCastException)

  • アンボクシング時、型が不一致の場合InvalidCastExceptionが発生する
object o = "hello";
int i = (int)o; //例外発生
object o = 42;
long l = (long)o; //例外発生
public class MyClass { public int x = 1; }
public struct MyStruct { public int x; }

MyClass m = new();
MyStruct s = (MyStruct)o; // 例外発生

ボクシングと明示的キャストの違い

  • メモリ上の扱いが異なる
  • 明示的キャスト:同じ値型同士の変換(例:floatint)
  • ボクシング:値型 → 参照型

実際に色々試してみた

使用したコード(トップレベルステートメントで作成)
Console.WriteLine("=== ボクシング: int → object ===");
int i = 123;
object boxed = i;
Console.WriteLine($"boxed: {boxed} (Type: {boxed.GetType()})");

Console.WriteLine("\n=== アンボクシング(成功): object → int ===");
int j = (int)boxed;
Console.WriteLine($"j: {j}");

Console.WriteLine("\n=== アンボクシング(失敗): ===");
try
{
    object str = "hello";
    int k = (int)str;
}
catch (InvalidCastException ex)
{
    Console.WriteLine($"例外発生: {ex.Message}");
}

Console.WriteLine("\n=== ボクシング時の型と異なる型にアンボクシング ===");
try
{
    object num = 42;
    long l = (long)num;
}
catch (InvalidCastException ex)
{
    Console.WriteLine($"例外発生: {ex.Message}");
}

Console.WriteLine("\n=== 値型同士のキャスト: float → int ===");
float f = 3.14f;
int fi = (int)f;
Console.WriteLine($"float -> int: {fi}");

Console.WriteLine("\n=== 等価比較でのエラー ===");
int m = 100;
object om = m;
Console.WriteLine($"m == (int)om: {m == (int)om}"); //問題なし
//Console.WriteLine($"om == m: {om == m}");           //エラー:参照型と値型の比較

参考

発展

余談

  • System.Collectionsのコレクションは要素をobjectとして格納するのでボクシングの影響すごそう

Discussion