Le boxing est la conversion d’un type valeur (int, bool, double, struct) en un object ou une interface. Le runtime copie la valeur vers le tas (heap).
int x = 42;
object obj = x; // boxing automatique
Le boxing est implicite et peut créer des allocations inutiles.
L’unboxing est l’opération inverse : extraire la valeur depuis l’objet boxé. Il doit être explicite car C# exige le type exact.
object obj = 42;
int y = (int)obj; // unboxing
object o = 10; // boxing
void Print(object o) => Console.WriteLine(o);
Print(123); // boxing
ArrayList list = new ArrayList();
list.Add(5); // boxing
public interface IPrintable { void Print(); }
public struct Point : IPrintable {
public int X, Y;
public void Print() => Console.WriteLine($"{X},{Y}");
}
IPrintable p = new Point( ); // boxing
IPrintable p = new Point { X = 10, Y = 20 };
p.Print(); // boxing automatique
L’appel via une interface exige une référence → boxing.
public static void Call(T value) where T : IPrintable {
value.Print(); // boxing si T est une struct
}
public static void PrintFast(this T v)
where T : struct, IPrintable
{
v.Print(); // aucun boxing !
}
public interface IWrapper { T Value { get; } }
public struct Wrapper : IWrapper {
public T Value { get; init; }
}
Wrapper w = new Wrapper { Value = 10 };
IWrapper iw = w; // boxing
int v = iw.Value; // unboxing du T
object o = 42;
// ❌ InvalidCastException
double d = (double)o;
L’unboxing doit récupérer le type exact.
Un million de boxings peut multiplier le temps par 30 à 100.
public interface ICompute {
int Compute(int x);
}
public struct AddOne : ICompute {
public int Compute(int x) => x + 1;
}
public int Work(T algo) where T : ICompute {
int sum = 0;
for (int i = 0; i < 1_000_000; i++)
sum += algo.Compute(i); // BOXING à chaque appel !
return sum;
}
public int Work(T algo) where T : struct, ICompute {
int sum = 0;
for (int i = 0; i < 1_000_000; i++)
sum += algo.Compute(i); // aucun boxing
return sum;
}
object dans les API modernes
Boxing : struct → object / interface (implicite)
Unboxing : object → struct (explicite + cast)
Problème : allocations, lenteur, GC, bugs
Solution : generics, struct constraints