A: Boxing and unboxing enable type system unification.
The goal of type system unification is to bridge the gap between value types
and reference types that exists in most languages. For example, a Stack class
can provide Push and Pop methods that take and return object values.
| public class Stack { public object Pop() {...} public void Push(object o) {...} } |
Because C# has a unified type system, the Stack class can be used with elements
of any type, including value types like int.
No, not really. Reference types have the concept of identity and equality,
while value types only have equality. Boxing and unboxing does not change this
fundamental difference.
Autoboxing in C# allows value types to go back and
forth between being objects, but each time a value type becomes an object
it acquires a new identity.
Here's a sample program to illustrate this problem:
| using System;
struct A { }
class B { }
public class Test { static Object Process(Object o) { if (o is A) { A a = (A)o; // do something with a return a; } else if (o is B) { B b = (B)o; // do something with b return b; } return null; }
static void Check(Object o) { Console.WriteLine(o == Process(o)); }
public static void Main(string[] args) { Check(new A()); Check(new B()); } } |
This program prints
which may be unexpected if you don't understand that value types and
reference types cannot be treated the same way. This illustrates the
fact that C# does not bridge the gap between value types and reference
types.
The solution to this problem is to use wrapper classes. Pretending
there is no difference between reference types and value types
is dangerous as it will invariably result in hard-to-detect bugs,
as demonstrated by this example.
A: A boxing conversion always makes 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. For example,
given the declaration
| struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } |
the following statements
| Point p = new Point(10, 10); object box = p; p.x = 20; Console.Write(((Point)box).x);
|
will output the value 10 because the implicit boxing operation that occurs
in the assignment of p to box causes the value of p to be copied. Had Point
been declared a class instead, the value 20 would be output because p and
box would reference the same instance.
A: Yes, but note that if you store a value type in a collection, then in order
to update the value you have to unbox, update the value, rebox the updated value
and then replace the object in the collection. This has two problems:
- Performance. As
this article
shows, you can almost double performance by using wrapper classes
(see IntHolderClass)
instead of autoboxing.
- Loss of identity. The updated object is not the same as the old object.
This can break code that depends on the identity of the object. Again, this
problem can also be solved by using a wrapper class.
A: The 'Type System Unification' in C# is half-baked and full of pitfalls.
C# Best Practice
Do not use boxing and unboxing
|
[Back to Index]
|