Boxing and Unboxing in .NET
I realized that the way boxing and unboxing works in .NET was not something I knew well, so I decided to write some small recap along with code to test boxing/unboxing behaviors.
Some Theory
In .NET, even if value types derive from the uber root object System.Object, they need the special boxing operation to be treaded as object.
A good explanation is given in the C# Language Specification:
A value of a class type can be converted to type
object
or to an interface type that is implemented by the class simply by treating the reference as another type at compile-time. Likewise, a value of typeobject
or a value of an interface type can be converted back to a class type without changing the reference (but of course a run-time type check is required in this case).Since structs are not reference types, these operations are implemented differently for struct types. When a value of a struct type is converted to type
object
or to an interface type that is implemented by the struct, a boxing operation takes place. Likewise, when a value of typeobject
or a value of an interface type is converted back to a struct type, an unboxing operation takes place.
So, when a value type needs to be converted to an object, it is boxed in a reference type. As stated, boxing means that the value type gets copied in the wrapping reference type.
A boxing conversion implies making a copy of the value being boxed. This is different from a conversion of a reference-type to type
object
, in which the value continues to reference the same instance and simply is regarded as the less derived typeobject
.
The important thing to bear in mind is that boxing and unboxing happens automatically. Everywhere an reference type is expected but a value type is used instead, the value type is automatically boxed.
Another important point is that if the value type has overrides some of the virtual methods inherited from object, invocation of these methods on the value type does not require boxing.
Some Examples
Now, let’s see how it works, and what are the caveats.
A first interesting case is directly taken from Bill Wagner’s “Effective C#”. Consider this code:
Console.WriteLine("A few numbers:{0}, {1}, {2}", 25, 32, 50);
WriteLine takes an array of object references as parameters. This means that the three value types will be boxed before calling the ToString() method on them. To avoid this, ToString() method should explicitely be called on each of these int in order to provide WriteLine with string which are reference types, so there is no boxing.
Console.WriteLine("A few numbers:{0}, {1}, {2}", 25.ToString(), 32.ToString(), 50.ToString());
So, that’s one thing to keep in mind. It’s good for performances reasons, but it doesn’t introduce any bug.
The next step is the copy of the value type in the box itself, meaning that any change to the copied value type in the box will not be reflected in the original copy. Also, when unboxing, the value from the box is copied again.
int i = 5; var j = (object)i; i++; Console.WriteLine("i: {0}", i); //Prints 6 Console.WriteLine("j: {0}", j); //Prints 5 j = (object)i; var k = (int)j; k++; Console.WriteLine("j: {0}", j); //Prints 6 Console.WriteLine("k: {0}", k); //Prints 7
When you think about it, is quite easy and it makes a lot of sense, as in C#, things are copied by value (meaning that when you copy a reference type, you copy the value of the reference, which is what the variable stores).
Last funny thing:
Object.ReferenceEquals(5, 5); //Returns false
It’s easy to understand. The two value types (5 and 5) are each boxed in a separate reference type, which don’t have the same reference.
A small warning tough, everything I write here is from quite trusted sources, but it may happen that I misunderstood something, so ask a real expert if you want to be sure…
blog comments powered by Disqus