Boxing คืออะไร?
Boxing คือการแปลง Value Type (struct, int, double, bool, etc.) ให้กลายเป็น Reference Type (object หรือ Interface) โดยการจัดสรรหน่วยความจำบน Heap และคัดลอกค่าไปอยู่ที่นั่น
Unboxing คืออะไร?
Unboxing คือกระบวนการกลับกัน - แปลงจาก object กลับเป็น Value Type โดยคัดลอกค่าจาก Heap กลับไป Stack
ตัวอย่าง Boxing/Unboxing
using System;
using System.Collections.Generic;
public class Demo {
static void Main() {
int x = 50;
// Boxing: int (Stack) -> object (Heap)
object obj = x; // Implicit Boxing
// เปลี่ยนค่า x ไม่ส่งผลต่อ obj
x = 100;
Console.WriteLine("Value Type (x) = {0}", x); // 100
Console.WriteLine("Object Type (obj) = {0}", obj); // 50 - ค่าเดิม!
// Unboxing: object -> int (ต้อง Cast صريح)
int y = (int)obj; // Explicit Unboxing
Console.WriteLine("Unboxed: " + y); // 50
}
}
ผลลัพธ์
Value Type (x) = 100
Object Type (obj) = 50
Unboxed: 50
ภาพประกอบ Memory Layout
STACK HEAP
┌─────────┐ ┌─────────┐
│ int x │ Boxing (Copy) │ object │
│ 50 │ ───────────────▶ │ 50 │
└─────────┘ └─────────┘
│ │
│ x = 100 │ (Unchanged)
▼ ▼
┌─────────┐ ┌─────────┐
│ int x │ │ object │
│ 100 │ │ 50 │
└─────────┘ └─────────┘
Boxing/Unboxing ในทางปฏิบัติ
1. Non-Generic Collections (Legacy)
ArrayList list = new ArrayList();
list.Add(10); // Boxing: int → object
list.Add(20); // Boxing
int sum = (int)list[0] + (int)list[1]; // Unboxing ต้อง Cast
2. Interface Implementation
interface IPrintable {
void Print();
}
struct Point : IPrintable {
public int X, Y;
public void Print() => Console.WriteLine($"({X}, {Y})");
}
Point p = new Point { X = 1, Y = 2 };
IPrintable printable = p; // Boxing: struct → Interface
printable.Print();
3. String Formatting
int num = 42;
string s = string.Format("Value: {0}", num); // Boxing: int → object (params object[])
Performance Impact
| Operation | Cost |
|---|---|
| Boxing | Allocate Heap Memory + Copy Value + GC Pressure |
| Unboxing | Type Check + Copy Value from Heap |
| Total Overhead | ~10-20x ช้ากว่า Direct Value Access |
หลีกเลี่ยง Boxing - Best Practices
- ใช้ Generics (List<T>) แทน ArrayList/ArrayList
- ใช้ ValueTuple แทน Tuple<T> (Class)
- หลีกเลี่ยง
objectParameter สำหรับ Value Types - ใช้
Span<T>,Memory<T>สำหรับ High-Performance Scenarios - Override
ToString()เพื่อลด Boxing ใน String.Format
Generic Alternative (No Boxing)
// แทน ArrayList
List list = new List();
list.Add(10); // No Boxing!
list.Add(20); // No Boxing!
int sum = list[0] + list[1]; // No Unboxing! Direct Access
สรุป
- Boxing: Value Type → Object/Interface (Implicit, Heap Allocation)
- Unboxing: Object/Interface → Value Type (Explicit Cast, Copy from Heap)
- มี Performance Cost สูง - หลีกเลี่ยงใน Hot Paths
- ใช้ Generics (
List<T>) แทน Non-Generic Collections