Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

Boxing ใน C# คืออะไร

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)
  • หลีกเลี่ยง object Parameter สำหรับ 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