Boxing:
Value types are "lighter" than reference types because they are not allocated as objects in the managed heap, are not garbage collected, and are not referenced through pointers. But many times it is necessary to obtain a reference to a value type. For example, suppose you want to create an ArrayList object to hold a set of point structures. The code is as follows:
public sealed class Program
{
public static void Main()
{
ArrayList a = new ArrayList();
Point p; //Allocate a Point (not allocated in the heap)
for (int i = 0; i < 10; i++)
{
p.x = p.y = i; //Initialize members in the value type
a.Add(p); //Box the value type and add the reference to the ArrayList
}
}
}
Every loop iteration initializes a ponit value type field and stores the point in the ArrayList. But think about what exactly is stored in ArrayList? Is it a Point structure, the address of a Point structure, or something else entirely? To know the correct answer, you must study the Add method of ArrayList to understand what type its parameters are defined as. The prototype of the Add method in this example is as follows:
public virtual int Add (Object value);
It can be seen that Add gets an Object parameter, that is to say, Add gets the object on the managed heap A reference to an object as a parameter. But the previous code passed p, which is a Point, which is a value type. In order for the code to work correctly, the Point value type must be converted to a real object hosted on the heap, and a reference to the object must be obtained.
The boxing mechanism is used to convert value types into reference types. Let's talk about what happens when an instance of a value type is boxed:
1, allocate memory in the managed heap. The amount of memory allocated is the amount of memory required for each field of the value type, plus the amount of memory required for the two additional members (the type object pointer and the synchronization block index) that all objects in the managed heap have.
2. Copy the value type field to the newly allocated heap memory
3, and return the object address. Now the object is an object reference; the value type becomes a reference type
The C# compiler detects that the above code is passing a value type to a method that requires a reference type, so it automatically generates code to box the object. So at runtime, the fields currently present in the Point value type instance p are copied into the newly allocated Point object. The address of the boxed Point object (now a reference type) is returned and passed to the Add method. Point objects remain in the heap until they are garbage collected. Point value type variable p can be reused because ArrayList does not know anything about it. In this case, the lifetime of the boxed type exceeds the lifetime of the boxed value type.
Unboxing:
Suppose you want to use the following code to get the first element of ArrayList:
Point p=(Point)a[0] ;
He gets the reference contained in element 0 of the ArrayList, and the view puts it into the instance p of the Point value type. To do this, all fields in the boxed Point object must be copied into value type variables, which are on the thread stack. The CLR completes the copy in two steps. The first step is to obtain the address of each Point field in the boxed Point object. This process is called unboxing. The second part copies the value contained in the field from the heap to the stack-based value type instance
Unboxing does not directly reverse the boxing process. Unboxing is much lower code than boxing. Unboxing is essentially the process of obtaining a pointer to a primitive value type contained in an object. In fact, the pointer points to the unboxed part of the boxed instance. Therefore, unlike boxing, Chaxiang does not require any bytes to be copied in memory. After knowing this important difference, another important point to know is that it is often followed by a field copy.
When a boxed value type instance is unboxed, the following things happen internally:
1. If the variable containing "a reference to the boxed value type" is null, throw NullReferenceException
2, if the referenced object is not a boxed instance of the required value type, throw InvalidCastException
The second one means the work of the code The method may be different from what you think:
public static void Main()
{
Int32 x = 5;
Object o = x; //Box x, o refers to the boxed object
Int16 y = (Int16)o; //Throws InvalidCastException
}
Logically speaking , it is completely possible to obtain the boxed Int32 referenced by o and force it to be converted to int16. However, when unboxing the object, it can only be converted to the original unboxed value type - Int32 in this case. The following is the correct way to write it:
public static void Main()
{
Int32 x = 5;
Object o = x; //Boxing x, o reference has been Boxing object
Int16 y = (Int16)(Int32)o; //Unbox it to the correct type first, and then transform it
}
Looking at the following code:
public static void Main()
{
Point p;
p.x = p.y = 1;
Object o = p; //Box p, o refers to the boxed instance
//Change the x field of Point to 2
p = (Point)o; //Unbox o and copy the fields from the boxed instance to the stack variable
p.x = 2; //Change the state of the stack variable
o = p; //Box p, o refers to the new boxed instance
}
The only purpose of the last three lines of code is to change the x field of Point from 1 Becomes 2. To do this, first perform an unboxing, then perform a field copy, then change the field (on the stack), and finally perform a boxing (create a brand new boxed instance on the managed heap). This shows the impact of boxing and unboxing on application performance.
Ask:
public static void Main()
{
Int32 v = 5;
Object o = v;
v = 123;
Console.WriteLine(v+","+(Int32)o);
}
How many times has the above code occurred? box?
The above is the detailed content of Example tutorial on packing and unboxing. For more information, please follow other related articles on the PHP Chinese website!