Packing and unpacking are. A very important concept in net.
Boxing is the conversion of a value type to a reference type, or a value type that implements an interface. Boxing dumps the data storage space from the thread stack into the managed heap. Any space in the managed heap will trigger a GC (garbage collection), and the thread statck will not trigger a garbage collection.
Unpacking is extracting data from the managed heap and copying it into the thread stack. So unpacking will form two data, one in managed heap and one in thread statck.
Let's take a look at the code for boxing and unpacking.
public static void Boxunbox () { int i = 123; Object o = i;//implicitly boxed object P= (object) i;//Explicit boxing int j = (int) p;//unpacking }
Il's Code
Stack diagram
You can see that I to O, I to P are boxed, and that the O and P data are stored in the managed heap. While P to J is unboxing, the data is copied to the thread stack.
Boxing can be explicit or implicit, but unpacking is explicit. At first glance, boxing and unpacking are reciprocal operations, but you can see that this is not the case. Boxing requires space in the managed heap while the corresponding pointer (Type object PTR) and Synchronous block index (Sync Bolck index) must be set in space before the data in the thread stack is copied. While unpacking, the data is copied from the managed heap to the thread stack, immediately after the corresponding field. So boxing and unpacking are not completely reciprocal operations. And from the consumption, the cost of unpacking will be less than the consumption of boxing.
Let's take a look at some test code
Internal struct point { private Int32 _x, _y; Public point (Int32 x, Int32 y) { _x = x; _y = y; } public void Change (Int32 x, Int32 y) { _x = x; _y = y; } public override String ToString () { return String.Format ("({0}, {1})", _x.tostring (), _y.tostring ()); } } public static void TypeTest () {point p = new Point (1, 1); Console.WriteLine ("P:" +p); P.change (2, 2); Console.WriteLine ("P:" + P); Object o = p; Console.WriteLine ("O:" +o); (point) O). Change (3, 3); Console.WriteLine ("O:" + O); }
Output results
As you can see from the results, the P initial value is (+), so the first output is (in). After the change function, the second output is (2,2). When P is converted to O, the output O is (3,3). This is all to be expected.
However, after the (point) O strong turn and the change (3,3) is executed, the output is not expected (3,3). Why is this?
We can know from the previous thread stack and managed heap comparison that when the object o is disassembled to point, the data of O is copied to the thread statck, so that the change (3,3) is only for thread STATCK, while the data at output is also o in the managed heap. Such a thought, the result has become taken for granted.
What if you inherit point from an interface? And what will happen? To differentiate from point, this place point becomes pointex. The code is as follows
Interface defining a Change method internal Interface ichangeboxedpoint {void Change (Int32 x, Int32 y) ; }//point is a value type. Internal struct Pointex:ichangeboxedpoint {private Int32 _x, _y; Public Pointex (Int32 x, Int32 y) {_x = x; _y = y; The public void change (Int32 x, Int32 y) {_x = x; _y = y; } public override String ToString () {return String.Format ("({0}, {1})", _x.tostring (), _y.tostri Ng ()); }} public static void Typetestpointex () {Pointex p = new Pointex (1, 1); Console.WriteLine (P); P.change (2, 2); Console.WriteLine (P); Object o = p; Console.WriteLine (o); ((Pointex) o). Change (3, 3); Console.WriteLine (o); Boxes p, changes the boxed object and discards it ((Ichangeboxedpoint) p). Change (4, 4);Console.WriteLine (P); Changes the boxed object and shows it ((Ichangeboxedpoint) o). Change (5, 5); Console.WriteLine (o); }
Results such as
As you can see from the results, the P initial value is (+), so the first output is (in). After the change function, the second output is (2,2). Turn o strong to Pointex and perform change (3,3), Output is (2,2). This has been interpreted in the previous example. That (Ichangedboxedpoint) strong turn P and O output is the result of why (2,2) and (5,5).
Think about the thread statck and managed Heap in front of you. When P is Ichangedboxedpoint cast, it is boxed (box), and the managed heap opens up a space to store the x and y of point, where the change operation is performed and the GC is triggered. The GC automatically reclaims this portion of the space when the changed return is performed. P is also the original p in the thread stack. So the output is (2,2).
For the Ichangedboxedpoint cast O, there would have been a boxing operation, but here the O is an object, is already boxed, so no longer boxed. So change (5,5) changes the data here, and since Ichangedboxedpoint returns after executing the switch, because of the use of the O-space data, and o exists, so the life cycle does not end, the GC will not reclaim this part of the data. So the output is (5,5).
Thus, we can think about this code
public static void Testwriteline () { int i = 1; Console.WriteLine ("{0},{1},{2}", i,i,i); Object o = i; Console.WriteLine ("{0},{1},{2}", O,o,o); }
The results of the two Console.WriteLine outputs are the same, but there are differences in the interior. Let's take a look at the IL code
You can see that the Console.WriteLine ("{0},{1},{2}", I,i,i) is boxed three times because Console.WriteLine is calling a method of three obj parameters, see. I is an int type, a value type, to be converted to an object, so a boxing operation is required, because it is three obj, so there are three boxing (box).
Then look at Console.WriteLine ("{0},{1},{2}", O,o,o), only a boxing operation, and Console.WriteLine is called another method, see. Here the I is boxed by the object o, so the subsequent Console.WriteLine call will no longer need to be boxed.
Thus, it can be seen that although the output of the same results, but because of the number of internal boxing operations are different, it can be foreseen that the performance of the latter is necessarily superior to the former.
In conclusion, we can draw the following conclusions:
1. Boxing is the conversion of a value type to a reference type, or a value type that inherits an interface. If the boxed value type needs to change the internal field, it needs to be implemented via an interface.
2. When boxing, it is necessary to open the corresponding space in the managed heap and trigger the GC.
3. When unpacking, a copy of the data from the managed HEADP is copied to the thread stack.
4. Packing and unpacking are not completely reciprocal.
5. The cost of unpacking is less than the consumption of boxing.
Instructions attached to MSDN http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx
Reprint please specify the source http://blog.csdn.net/xxdddail/article/details/36892781