5th. Primitive types, reference types, and value types

Source: Internet
Author: User

5.1 Primitive types for programming languages

The data types directly supported by the compiler (Compiler) are called primitive types (primitive type).

I want the compiler not to provide primitive type names at all, forcing developers to use the FCL (Framework class Library) type name:

Many developers are puzzled whether a string or string should be used. Because the String of C # is mapped directly to System.String, there is no difference between the two. int is always mapped to System.Int32, so whatever operating system is running, it represents a 32-bit integer.

5.2 Reference types and value types

Although most types in the FCL are reference types, the most common use for programmers is value types.

Value types: Primitive Types (Sbyte, Byte, short, Ushort, Int, Uint, Long, Ulong, Char, Float, Double, Bool, Decimal), enumeration (enum), struct (struct).

To improve the performance of simple common types, the CLR provides a lightweight type of value type. Instances of value types are generally allocated on the thread stack.

The reference type is always allocated from the managed heap, and the new operator of C # returns the memory address of the object-that is, the memory address that points to the object data.

There are four kinds of reference types: class type, interface type, array type, and delegate type. All references to the object referenced by the type variable, whose memory is allocated in the managed heap.

You must consider performance issues when using reference types, first consider the following facts:

    • Memory must be allocated from the managed heap
    • Each object allocated on the heap has some extra members (type object pointers, synchronous block indexes) that must be initialized
    • Other bytes in the object (set for field) are always set to zero
    • A garbage collection operation may be enforced when an object is allocated from the managed heap

In a variable that represents an instance of a value type, it does not contain a pointer to an instance. Instead, the variable contains the fields of the instance itself. Because the variable already contains the field of the instance, in order to manipulate the field in the instance, it is no longer necessary to pick up a pointer, the instance of the value type is not controlled by the garbage collector, and the system is automatically released if the scope is exceeded. Therefore, the use of value types mitigates the pressure in the managed heap and reduces the number of garbage collections that an application needs to make during its lifetime.

In the. Net Framework SDK documentation, any type called "Class" is a reference type. For example: The System.Exception class, the System.IO.FileStream class, and the System.Random class are reference types.

Instead, all value types are referred to as structs or enumerations in the document. For example: System.Int32 structure, System.TimeSpan structure, System.dayofweek enumeration. All structures are direct derived classes of abstract type System.ValueType. All enumerations are derived from the System.Enum abstract type. System.Enum is also derived from System.ValueType.

All value types are implicitly sealed (sealed) to prevent one value type from being used as the base type of any other reference or value type.

When you use a type in your code, you must be aware that the type is a reference type or a value type.

Someval v1 = new Someval ();

The preceding line of code appears to be allocating a someval instance on the managed heap. However, the C # compiler knows that Someval is a value type, so the corresponding IL code is generated and a Someval instance is allocated on the thread stack. C # also ensures that all fields in a value type are initialized to zero.

Only one type should be declared as a value type when the following conditions are met:

    • Type has the behavior of primitive types. No member of the type modifies any instance field of the type. In fact, for many value types, it is recommended that their fields be marked as ReadOnly
    • Type does not need to inherit from any other type
    • Type is not derived from any other type

Declaring a value type must satisfy any of the above 3 criteria:

    • Type is small (approximately 16 bytes or smaller)
    • The instance of the type is large, but not passed as an argument to the method, nor is it returned from the method

The difference between a value type and a reference type:

    • There are two representations of value types: unboxed (unboxed) Form and boxed (boxed) Form. In contrast, reference types are always in boxed form
    • Value types are derived from System.ValueType. This method provides the same method as defined by System.Object. However, System.ValueType overrides the Equals method to return True if the fields of two objects match exactly. System.ValueType overrides the GetHashCode method, the algorithm used by this override method takes into account the value of the instance field of the object when generating the hash code.
    • Because you cannot define a new value type or a new reference type as a base type, you cannot introduce any virtual methods in a value type. All methods cannot be abstract, and are implicitly sealed methods
    • A variable of a reference type points to the address of an object on the heap. By default, when a variable of a reference type is created, it is initialized to NULL, indicating that a variable of the reference type does not currently point to a valid object. An attempt to use a null reference-type variable throws a NullReferenceException exception. A variable of a value type always contains a value of its underlying type, and all members of the value type are initialized to 0. Because a variable of value type is not a pointer, it is not possible to throw a NullReferenceException exception when accessing a value type. The CLR provides a special attribute for value types that can add "nullability" to value types
    • Assigning a variable of a value type to another value type variable performs a verbatim copy of the segment (reassigning and copying members on the thread stack). When assigning a variable of a reference type to another reference type variable, only the memory address (instance/object of the same type in the heap) is copied. )
    • Based on the previous one, a variable of two or more reference types can refer to the same object in the heap, and all operations performed on one variable may affect the object referenced by another variable. Conversely, a variable of value type is an object of self-contained, and an operation on a value type variable cannot affect another value type variable
    • Since the unboxed value type is not allocated on the heap, once the method that defines an instance of that type is no longer active, the storage allocated for them is freed. This means that an instance of a value type will not receive a notification through the Finalize method when its memory is reclaimed

Private Static void Main () {int5new  MyClass ();}

When a local variable is declared, a chunk of memory is allocated to this variable in the memory of the stack, as to how large the memory is and what it holds inside it depends on whether the variable is a value type or a reference type.

    • Value type

If it is a value type, the size of the memory allocated for the variable is the size of the value type definition, which holds the value of the value type itself (content). For example, for the integer variable i above, the size of this memory is 4 bytes (the size defined by an int type), if I = 5, this line of code, then the contents of this block of memory is 5 (-1).

For any value type, either Read or write, you can one step because the memory of the value type variable itself holds the value.

    • Reference type

In the case of a reference type, the size of the memory allocated for a variable is the size of a memory pointer (instance reference, object reference) (4 bytes on a 32-bit system and 8 bytes on a 64-bit system). Because the instances (objects, values) of all reference types are created on the managed heap, the memory allocated for the variable holds the memory header (memory pointer) of the variable corresponding to the instance (object, value) on the heap, also called a reference to the instance (object).

As shown in Figure 2, the variable MC holds an object reference to the MyClass instance (object), and if access to the MC instance is required, the system needs to first get the instance reference (the address in the heap) from the MC variable, and then use the reference (address) to find the instance in the heap and then access it. You need at least 2 steps to complete the instance access.

5.3 Packing and unpacking of value types

A value type is a type that is more "lightweight" than a reference type because it is not allocated as an object in the managed heap, is not garbage collected, and is not referenced by pointers. In many cases, however, you need to get a reference to an instance of a value type that converts the value type to a reference type.

As the code above, create a ArrayList object (a type defined in the System.Collections namespace) to accommodate a set of point structures.

Each iteration of the loop initializes the value type fields (x and Y). The point is then stored in the ArrayList. But what exactly is stored in the ArrayList? Is the point structure, or something else. We must study ArrayList's Add method to see what type of parameter it is defined into.

Add needs to get an object parameter. In other words, add needs to get a reference (pointer) to an object on the managed heap as a parameter. But in the previous code, the Pass is P, which is a point, which is a value type. In order to convert a value type to a reference type, a mechanism called boxing (boxing) is used.

What happens internally when a boxing operation is performed on an instance of a value type:

    • Allocate good memory on the managed heap. The amount of memory that is allocated is the amount of memory required for each field of a value type plus two additional members (type object pointer and synchronization block index) for all objects in the managed heap
    • A field of value type is copied into the newly allocated heap memory
    • Returns the address of an object, which is a reference to an object, and the value type is now a reference type

The C # compiler automatically generates the IL code that is required to boxing an instance of a value type.

In the preceding code, the C # compiler detects that a value type is passed to a method that requires a reference type, so the code is automatically generated to boxing the object. At run time, the field that currently exists in the point value type instance p is copied to the newly assigned point object. The address of the boxed point object (now a reference type) is returned to the Add method. The point object persists in the heap until it is garbage collected. The point value type variable p can be reused because ArrayList does not know anything about it at all. In this case, the lifetime of the boxed value type exceeds the lifetime of the unboxed value type.

After you know how the boxing is done, then talk about unpacking.

Suppose you need to get the first element of ArrayList using the following code:

It is now time to get the reference (or pointer) contained in element 0 of ArrayList and attempt to place it in instance p of a point value type. All the fields contained in the boxed point object must be copied to the value type variable p, which is on the thread stack.

The CLR completes this copy operation in two steps (unpacking/copying).

The first step is to get the address of each point field in the boxed point object. This process is known as unboxing (unboxing)

The second step is to copy the values contained in these fields from the heap to the stack-based value type instance

Unpacking does not directly reverse the boxing process. The cost of unpacking is much lower than packing. Unpacking is actually the process of getting a pointer to the original value type (data field) contained in an object. Therefore, unlike boxing, unpacking does not require any bytes to be copied in memory, and it often occurs immediately after the unboxing operation, once the field is copied.

When an instance of a boxed value type is unpacking, the following things happen inside:

    • Throws a NullReferenceException exception if the variable containing the reference to the boxed value type instance is null
    • Throws an InvalidCastException exception if the reference to the object is not a boxed instance of the expected value type

Logically, the above code can fetch a boxed Int32 referenced by O and then cast it to a Int16. However, when unpacking an object, you can only transform it to a value type that was not boxed---This example is Int32

The following code is the correct notation:

Overload: Overloading refers to a method in the same class with two or more names but different parameters (number of arguments and parameter types).

Because the unboxed value type does not have a synchronized block index, you cannot use various methods of the System.Threading.Monitor type to allow multiple threads to synchronize access to this instance.

5.3.2 Object Equality and identity (re-viewing later)

Sometimes you need to put objects into a collection and write code to sort, search, or compare the objects in the collection.

For the default implementation of the Equals method of object, it implements the actual identity (identity) rather than equality (equality).

5.4 Object Hash code (see later)

Hash: The result of a fixed size that is obtained by applying a hashing algorithm to any number of data. If there is a change in the input data, the hash will also vary. Hash can be is used for many operations, including authentication and digital signatures. Also known as "Message Digest".

Hash table: A set of keywords are mapped to a limited address range based on the set hash function and the handling conflict method, and the key is stored in the table as a storage location in the address range, which is called a hash or hash, and the resulting storage location is called a hash address or hash address. As a linear data structure compared with tables and queues, the hash table is undoubtedly a faster search speed.

In. NETFramework, Hashtable is a container provided by the System.Collections namespace to handle and behave like a keyvalue key \ value pair. Where key is case-sensitive and is often used for quick lookups. Value is used to store values corresponding to key. The KeyValue key \ value pair in Hashtable is of type object, so hashtable can support any type of KeyValue key \ value pair.

Hashtable is a non-generic collection, so boxing and unboxing typically occur when you retrieve and store value types.

Add a keyvalue key \ value pair to the hash table: Hashtableobject.add (Key,value);

Remove a keyvalue key \ value pair in the hash table: Hashtableobject.remove (key);

Remove all elements from the hash table: Hashtableobject.clear ();

Determines whether a hash table contains a specific key key:HashtableObject.Contains (key);

Hashing algorithm: The binary value of any length is mapped to a small, fixed-length binary value, and this small binary value is called a hash value. A hash value is a unique and extremely compact numeric representation of a piece of data.

Hashcode identifies the address of an object that is used to distinguish between different objects.

The common search slow is because to a ratio, the hash is to let the comparison of the number of lower and lower the method is to rely on the calculation.

Based on the data you want to deposit, the algorithm calculates an address value, which is the location of the data that you need to deposit into the collection, instead of storing it one after the other as an array, and walking through the back of the table to save the situation. And when you look for it, it's based on the hash algorithm. Calculate the data you are looking for, get an address, this address will be mapped to the location of the collection, so you can go directly to this position to find, and do not need to like an array, a traversal, a comparison to find, so naturally increase the speed, improve efficiency.

If you can put any instance of any object into a Hashtable collection, there are many benefits. For this reason, System.Object provides a virtual method, GetHashCode, that can get the Int32 hash code for any object.

If you define a type that overrides the Equals method, you should also override the GetHashCode method to ensure that the equality algorithm and the object hash code algorithm are consistent. Because in the implementation of the System.Collections.Hashtable type, the System.Collections.Generic.Dictionary type, and some other collections, two objects must have the same hash code in order to be equal.

Simply put, when you add a key \ value pair to a collection, you first get a hash code for the key object. This hash code indicates which hash bucket (bucket) the key \ value pair should be stored in. When a collection needs to find a key, it gets the hash code for the specified key object. This hash code identifies the target hash bucket that is now being searched, in which to find a key object equal to the specified Key object. Using this algorithm to store and find keys means that once a key object in the collection has been modified, the collection can no longer find the object. Therefore, when you need to modify a key object in a hash table, it is a good practice to remove the original key \ value pair, modify the key object, and then add the new key \ value pair back to the Hashtable.

5.5 Dynamic Primitive Type

C # is a type-safe programming language. This means that all expressions are parsed into an instance of a type, and in the compiler-generated code, only the operations that are valid for that type are executed.

From an object-oriented perspective, an instance of an object represents an individual, and static properties and methods represent all the methods and properties that are common to all, such as "member Zhang San", "member John Doe" are the two individuals of the "member", the nickname, the rank is their different attributes, and the total number of members, registered new members are The properties and methods shared by all members. Double such as "circle" this class, radius, area, perimeter is the attribute of the individual, and Pi Pi is common.

From an application perspective, the essence is to save memory, with only one reference in memory.

The main functions of static classes are as follows:

    • They contain only static members.
    • They cannot be instantiated.
    • They are sealed.
    • They cannot contain instance constructors and cannot create instances of static classes using the New keyword.

In many cases, the program still needs to handle some messages that the runtime will know about. If you are writing a pure C # application, you will only be able to deal with information that is determined at run time when reflection is used. However, many developers use C # to communicate with components that are not implemented in C #. Some components are. NET dynamic languages, such as Python or Ruby, are HTML Document Object Model (DOM) objects.

The C # compiler allows you to mark the type of an expression as dynamic. You can also put the result of an expression into a variable and mark the type of the variable as dynamic. You can then invoke a member with this dynamic expression/variable, such as a field, property/indexer, method, delegate, and unary/two/conversion operator.

When code invokes a member with a dynamic expression/variable, the compiler generates a special IL code to describe the desired operation. This special code is called Payload (payload). When run, the payload code determines the specific operation based on the actual type of the object that is currently referenced by the dynamic expression/variable.

These payload code uses a class called the runtime Binder. The code of the runtime binder for C # is in the Microsoft.CSharp.dll assembly, which must be referenced when building a project that uses the dynamic keyword.

The Plus method declares the type of the parameter as dynamic, and within the method, the argument is used as two operands of the two-dollar + operator. Because ARG is dynamic, the C # compiler generates payload code that checks the actual type of ARG at run time and determines what the + operator actually does.

The first time you call Plus, you pass 5 (a Int32), so plus returns a value of 10 to its caller. The results are placed in the result variable (a dynamic type). Then call the M method and pass result to it. For calls to M, the compiler generates payload code to check the actual type of value passed to m at run time, and the overloaded version of the M method should be called.

The second time you call Plus, it's the same as the first time.

When a field type, method parameter, or method return type is specified as dynamic, the compiler converts the type to System.Object and in the metadata to the field, A parameter or method type applies an instance of System.Runtime.ComplierServices.DynamicAttribute. If a local variable is specified as dynamic, the variable type also becomes object, but Dynamicattribute is not applied to the local variable because its use is limited to the method.

At run time, the Microsoft.CSharp.dll assembly must be loaded into the AppDomain, which can damage the performance of the application and increase memory consumption. Although it is possible to simplify the syntax with dynamic features, it depends on whether it is worthwhile.

5th. Primitive types, reference types, and value types

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.