Value Types

Value Types

Value types are the closest thing in the common language runtime model to C++ structures. These types are values with either trivial structure (for example, a 4-byte integer) or complex structure. When you declare a variable of a class type, you don’t automatically create a class instance. You create only a reference to the class, initially pointing at nothing. But when you declare a variable of value type, the instance of this value type is created immediately, by the variable declaration itself, because a value type is primarily a data structure. As such, a value type must have instance fields or size defined. A zero-size value type (with no instance fields and no total size specified) represents invalid metadata; however, as in many other cases, the loader is more forgiving than the official metadata validity rules: when it encounters a zero-size value type, the loader assigns it a 1-byte size by default.

Although an instance of a value type is created at the moment a variable having this value type is declared, the instance constructor method (should it be defined for the value type in question) is not called at this moment. (See Chapter 9, “Methods,” for information about the instance constructor method.) Declaring a variable creates a “blank” instance of the value type, and if this value type has an instance constructor, it should be called explicitly.

Boxed and Unboxed Values

As a data structure, a value type must sometimes be represented as an object, to satisfy the requirements of certain generic APIs, which expect object references as input parameters. The common language runtime provides the means to produce a class representation of a value type and to restore a value type (data structure) from its class representation. These operations, called boxing and unboxing, respectively, are defined for every value type.

Recall from the beginning of this chapter that types can be classified as either value types or reference types. Simply put, boxing transforms a value type into a reference type (an object reference), and unboxing does just the opposite. We can box any value type and get an object reference, but this does not mean, however, that we can unbox any object and get a value type.

When we declare a value type variable, we create a data structure. When we box this variable, an object (a class instance) is created whose data part is an exact bit copy of the data structure. Then we can deal with this instance the same way we would deal with an ordinary object—for example, we could use it in a call to a method, which takes a generic object reference as a parameter. It is important to understand that the “original” variable does not go anywhere when it is being boxed.

Instance Members of Value Types

Value types, like other types, can have static and instance members, including methods and fields. To access an instance member of a class, we need to provide the instance pointer (known in C++ as this). In the case of a value type, we simply use a managed reference as an instance pointer.

Let’s suppose, for example, that we have a variable of type 4-byte integer. (What can be more trivial than that, except maybe type fewer-byte integer?) This value type is defined as [mscorlib]System.Int32 in the .NET Framework class library. Instead of boxing this variable and getting a reference to an instance of System.Int32 as the class, we can simply take the reference to this variable and call the instance methods of this value type, say, ToString( ), which returns a string representation of the integer in question:

 .locals init (int32 J)  // Declare variable J as value type   ldc.i4 12345 stloc J   // J = 12345  ldloca J // Get managed reference to J as instance pointer // Call method of this instance call instance string [mscorlib]System.Int32::ToString()  

Derivation of Value Types

All value types are derived from the [mscorlib]System.ValueType class. More than that, anything derived from [mscorlib]System.ValueType is a value type by definition, with one important exception: the [mscorlib]System.Enum class, which is a parent of all enumerators (discussed in the next section).

Unlike C++, in which derivation of a structure from another structure is commonplace, the common language runtime object model does not allow any derivations from value types. All value types must be sealed. (And you probably thought I was too lazy to draw further derivation branches from value types in Figure 6-1!)



Inside Microsoft. NET IL Assembler
Inside Microsoft .NET IL Assembler
ISBN: 0735615470
EAN: 2147483647
Year: 2005
Pages: 147
Authors: SERGE LIDIN

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net