1

I was studying boxing and unboxing.

I went through this example, I am unable to understand the answer.

Can anyone explain to me please.

I know what boxing and unboxing does now, by looking at a simple example, but this example, confuses a bit.

An example of boxing and then unboxing, a tricky example.

[struct|class] Point {
    public int x, y;    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}    
Point p = new Point(1, 1);
object o = p; p.x = 2;
Console.WriteLine(((Point)o).x);

I read the answer as:

It depends! If Point is a struct then the output is 1 but if Point is a class then the output is 2! A boxing conversion makes a copy of the value being boxed explaining the difference in behavior.

Here is ((point)o).x a boxing or unboxing?

Didn't understand, can anyone explain to me please.

I know that the answer should come 1, but if class then how 2?

Adel Khayata
  • 2,717
  • 10
  • 28
  • 46
user2387900
  • 215
  • 1
  • 6
  • 13
  • 3
    There's a preview pane when you write a post. You should look at it every once in a while so that others don't have to fix your bad formatting. – spender Aug 05 '13 at 01:49
  • This is a *very bad* example. The result is the same even without the boxing! That is, even if you change the `object o` to `Point o`, the output is the same. – Gabe Aug 05 '13 at 02:07
  • @Gabe: While what you say is true, it's not a bad example because you will run into people who hear that boxing means a unification of value types and reference types, and think that boxed types will behave like reference types. That is, an unfortunate common fallacy is that people think boxing a value type means, conceptually, drawing a box around an existing instance of a value type, not realizing that it actually means making a copy to put in the box. The point of the example is to show the difference between references arising from boxed value types, and references to reference types. – jason Aug 05 '13 at 03:05
  • @Gabe: So unfortunately, while people *might* and often *do* get that `int i = 42; int j = i;` makes a copy of `i`, what people often *don't* get is that `object o = i` does too. [People really do mistakenly believe](http://stackoverflow.com/questions/4732925/boxing-do-i-get-it-right) that changing the value of a value type will change the values in boxes that come from boxing that value type. Again, it seems that they think the boxing makes a reference to the original instance, missing that it actually makes a copy. – jason Aug 05 '13 at 03:10

5 Answers5

4

I don't know why everyone is writing an essay, it's pretty simple to explain:

  • When you cast a struct into object, it is copied into a new object.

  • When you cast an object into a struct, it is copied into a new struct.

  • When you cast between classes, the object's contents are not copied; only the reference is copied.

Hope that helps.

user541686
  • 205,094
  • 128
  • 528
  • 886
1

Although C# tries to pretend that structure types derive from Object, that's only half true. According to the CLI spec, a structure type specification actually defines two kinds of thing: a type of heap object which derives from System.ValueType (and in turn System.Object), and a kind of storage location (local variable, static variable, class field, struct field, parameter, or array slot) which does not derive from anything, but is implicitly convertible to the heap object type.

Every heap object instance contains all the fields defined by the type or its parent classes (if any), along with a header which identifies its type and some other information about the instance. Every struct-type storage location contains either the bytes necessary to hold its value (if a primitive type), or else holds the concatenated values of all its fields; in neither case does it contain any sort of header that identifies its type. Instead, value types rely upon information in the generated code to know what they are.

If one stores a value type to a storage location of that value type, the compiler will overwrite all the bytes occupied by the destination with values taken from the original value type. If, however, one tries to store a value type to a reference-type storage location (like Object), the runtime will generate a new heap object with enough space to hold all the data from the value type, along with a header identifying its type, and store in the destination location a reference to that new object. If one tries to typecast a reference type to a value type, the runtime will first verify that the object is of the proper type and, if so, copy the data from the heap object to the destination.

There are a couple of tricky scenarios involving interfaces and generics. Interface types are reference types, but if a struct implements an interface, the implementing methods may act directly upon a boxed struct instance without having to unbox and rebox it. Further, interface types used as generic constraints do not require boxing. If one passes a variable of a value type like List<int>.Enumerator to a function EnumerateThings<TEnumerator>(ref TEnumerator it) where TEnumerator: IEnumerator<int>, that method will be able to accept a reference to that variable without boxing.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

Since Point is Struct and Structs are value types which means they are copied when they are passed around.

So if you change a copy you are changing only that copy, not the original.

However if Point was a class, then it was passed by reference.

So if you change a copy you are changing only that copy and also the original.

As for your confusion

object o = p; is boxing

whereas

(Point)o is unboxing
Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
0

To understand boxing you need to understand the difference between Value types and Reference types.

I think the simplest way to understand it is:

"Value types are allocated in-line. Reference types are always allocated on the Heap"

meaning, that if you add a value type (struct, int, float, bool) inside of a reference-type as a class variable (public or private), that value-type's data is embedded wherever that reference-type lives on the Heap.

If you create a value-type inside of a function, but do NOT assign it to a public/private variable, that value-type is allocated in the Function-Stack (meaning once you leave that function it will get collected)

So, given that background knowledge, it should be pretty self-explanatory what happens when you "box" a value-type: you have to take that value type (wherever it was in-line allocated) and turn it into a reference-type (create a new object for it on the Heap).

JasonS
  • 7,443
  • 5
  • 41
  • 61
  • Don't know why the down-vote. Saying value types are allocated "in-line" is more accurate than saying they're on the stack, though the term "in-line" might be somewhat confusing. Using and defining 'storage location" would be better. – supercat Aug 05 '13 at 02:41
0

First you need to know where objects are stored. Structs, enums and other value types are stored on the stack, in registers, or on the heap; classes and other reference types are stored on the heap. A good tutorial is here.

Boxing is done when a value type is being stored in a heap. A copy is being made from stack to heap. Unboxing is the other way around, a copy of a value will be made from heap to stack.

   1 Point p = new Point(1, 1);
   2 object o = p; 
   3 p.x = 2;
   4 Console.WriteLine(((Point)o).x);

In your code above, if Point is a struct, a copy will be made to object "o". On your line 3, what you modified is is the Point in stack. On the last line you unboxed the object "o" but the value you will get is the copied value from the heap.

If the Point is class, in line 1, a space is created for the Point in the heap. Line 2, creates a new variable "o" that references to the same memory space. Remember that "p" & "o" are referencing on the same memory address location, so if you modify any of the variable just like in line 3, you will get the modified value on both variable.

Gabe
  • 84,912
  • 12
  • 139
  • 238
hallie
  • 2,760
  • 19
  • 27
  • Structs are stored in *storage locations*, which may be automatic variables, static variables, struct fields, class fields, array slots, or parameters. If a struct-type storage location is on the stack, the struct will be as well, but if it's a class field or array element the struct will be stored *within* an object on the heap. – supercat Aug 05 '13 at 02:39
  • @supercat: yes i agree, what i've given is a basic understanding of value types & reference types. – hallie Aug 05 '13 at 02:58
  • To say value types *can* be stored on the stack would be correct. To say that they *are* stored on the stack is in many cases, just plain wrong. – supercat Aug 05 '13 at 03:27