In short, I think boxing is an annoyance. Let's look at some alternatives...
public class Box<T>
where T : struct
{
public T Value { get; set; }
public static implicit operator T(Box<T> box)
{
return box.Value;
}
}
System.Int32 derives from abstract class System.ValueType which derives from class System.Object. You cannot derive from System.ValueType in C# but I would guess that the struct keyword does exactly that and the CLI recognizes these kind of type definitions as having pass-by-value semantic. Anyhow, when a struct is assigned to type of object boxing occurs. I don't wanna get caught up in boxing per se, instead I wanna get straight to it.
I looked at some of the IL generated by the C# compiler.
object obj = 1;
.locals init ([0] object obj)
L_0000: nop
L_0001: ldc.i4.1
L_0002: box int32 // Convert a value type (of the type specified in valTypeToken) to a true object reference.
L_0007: stloc.0
Found this on MSDN...
A value type has two separate representations within the Common Language Infrastructure (CLI):
A 'raw' form used when a value type is embedded within another object or on the stack.
A 'boxed' form, where the data in the value type is wrapped (boxed) into an object so it can exist as an independent entity.
This have lead me to conclude that it should be equally expensive to write code like this...
var box = obj as Box<int>;
if (box != null)
{
Console.WriteLine(box.Value);
}
If I intend to pass that same value around as an System.Object do I really wanna unbox and box the ValueType every time? My gut feeling is telling me no, but I cant really find good motivation anyone care to comment on all this blabbering?
EDIT
Anyone ever find themselves doing this? I realize that it might look bizarre but at one point I found myself in a position were I wanted to abstract computations based of several different representations. I did it like this and with lambda expressions. Its not really related to boxing but it sort of allowed me to treat any ValueType (this struct is conveniently 8-byte aligned) as if it were one single type "ReinterpretCast".
[StructLayout(LayoutKind.Explicit)]
public struct ReinterpretCast
{
[FieldOffset(0)] sbyte @sbyte;
[FieldOffset(0)] byte @byte;
[FieldOffset(0)] short @ushort;
[FieldOffset(0)] ushort @short;
[FieldOffset(0)] int @int;
[FieldOffset(0)] uint @uint;
[FieldOffset(0)] long @long;
[FieldOffset(0)] ulong @ulong;
[FieldOffset(0)] float @float;
[FieldOffset(0)] double @double;
}