"Go" C # explain the difference between value types and reference types

Source: Internet
Author: User
First, what is a value type and what is a reference type?

In C #, a value type variable stores data directly, while a reference type variable holds a reference to the data, and the data is stored in the data heap.

Value type: byte, short, int, long, float, double, decimal, char, bool, and struct are collectively called value types. After a value type variable is declared, the compiler allocates memory for it, regardless of whether it has been assigned a value.



Reference type (reference type): string and class are collectively referred to as reference types. When a class is declared, only a small piece of memory is allocated on the stack to hold an address, and no memory space on the heap is allocated for it. When you use new to create an instance of a class, the space on the heap is allocated, and the address of the space on the heap is stored in the small piece of space allocated on the stack.



Instances of value types are usually allocated on the thread stack (static allocation), but in some cases can be stored on the heap. Objects of reference type are always allocated (dynamically allocated) in the process heap.

The following example illustrates the difference between value types and reference types. The code is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Parameters
{
    class Program
    {
        static void Main (string [] args)
        {
            Dowork ();
        }
 
        static void Dowork ()
        {
            int i = 0; // int is a value type
            Console.WriteLine (i); // i = 0
            Pass.value (i); // The value type uses a copy of i, i is unchanged
            Console.WriteLine (i); // i = 0
 
            WrappendInt wi = new WrappendInt (); // Create another instance of the class WrappendInt
            Console.WriteLine (wi.Number); // 0 // initialized to 0 by the default constructor
            Pass.Reference (wi); // call the method, wi and param will refer to the same object
            Console.WriteLine (wi.Number); // 42
        }
    }
 
    class Pass
    {
        public static void value (int param)
        {
            param = 42; // the assignment operation uses a copy of the value type parameter, the original parameter is not affected
        }
 
        public static void Reference (WrappendInt param) // Create an instance of the class WrappendInt
        {
            param.Number = 42; // this parameter is a parameter of reference type
        }
    }
 
    class WrappendInt // class is a reference type
    {
        public int Number;
    }
}

The output is:
0

0

0

42



Conceptually, a value type stores its value directly, while a reference type stores a reference to its value. These two types are stored in different places in memory. In C #, we must determine the behavior of a type instance when designing a type. This decision is very important, in the words of CLR via C # author Jeffrey Richter, "A programmer who does not understand the difference between reference types and value types will introduce weird bugs and performance issues to the code (I believe that a developer who misunderstands the difference between reference types and value types will introduce subtle bugs and performance issues into their code. ". This requires us to properly understand and use value types and reference types.

Universal type system
In C #, whether a variable is a value or a reference depends only on its data type.

C # 's basic data types are defined in a platform-independent manner. C # 's predefined types are not built into the language, but rather into the .NET Framework. .NET uses the Common Type System (CTS) to define predefined data types that can be used in the intermediate language (IL). All .NET-oriented languages are eventually compiled to IL, that is, to CTS type-based code.

For example, when declaring an int variable in C #, the declaration is actually an instance of System.Int32 in CTS. This has important implications:

Ensure mandatory type safety on the IL;
Achieve interoperability between different .NET languages;
All data types are objects. They can have methods, properties, etc. E.g:
int;
i = 1
string;
s = i.ToString ();

This MSDN diagram illustrates how the various types in CTS are related. Note that instances of types can be just value types or self-describing types, even if those types have subcategories.


Value type
All value types in C # are implicitly derived from System.ValueType:

Structure: struct (derived directly from System.ValueType);
Value type:
Integer: sbyte (alias of System.SByte), short (System.Int16), int (System.Int32), long (System.Int64), byte (System.Byte), ushort (System.UInt16), uint (System .UInt32), ulong (System.UInt64), char (System.Char);
Floating point: float (System.Single), double (System.Double);
High precision decimal type for financial calculations: decimal (System.Decimal).
bool type: bool (alias of System.Boolean);
User-defined structure (derived from System.ValueType).
Enumeration: enum (derived from System.Enum);
Nullable types (derived from the System.Nullable <T> generic structure, T? Is actually an alias for System.Nullable <T>).
Each value type has an implicit default constructor to initialize the type's default value. E.g:

int = new new ();
Equivalent to:

Int32 i = new Int32 ();
Equivalent to:

int i = 0;
Equivalent to:

Int32 i = 0;

When using the new operator, a specific type of default constructor is called and a variable is assigned a default value. In the above example, the default constructor assigns the value 0 to i. A complete list of default values is available on MSDN.

All value types are sealed, so new value types cannot be derived.

It is worth noting that both the reference type and the value type are inherited from the System.Object class. The difference is that almost all reference types inherit directly from System.Object, while value types inherit their subclasses, that is, directly inherit System.ValueType. System.ValueType is derived directly from System.Object. That is, System.ValueType is itself a class type, not a value type. The key is that ValueType overrides the Equals () method, so that the value types are compared according to the value of the instance, rather than the reference address.

You can use the Type.IsValueType property to determine whether a type is a value type:

TestType testType = new TestType ();
if (testTypetype.GetType (). IsValueType)
{
Console.WriteLine ("{0} is value type.", TestType.ToString ());
}

3. Reference types
C # has the following reference types:

Array (derived from System.Array)
The following types are defined by the user:
Class: class (derived from System.Object);
Interface: interface (interface is not a "thing", so there is no question of where it is derived. Anders said in "C # Programming Language", interface is just a convention [contract])
Delegate: delegate (derived from System.Delegate).
object (alias of System.Object);
String: string (alias of System.String).
As can be seen:

Reference types are the same as value types. Structures can also implement interfaces;
Reference types can derive new types, while value types cannot;
Reference types can contain null values, value types cannot (nullable type functionality allows nulls to be assigned to value types);
Assignment of a reference type variable copies only a reference to the object, not the object itself. When you assign a value type variable to another value type variable, the contained value is copied.
For the last one, what is often confused is string. I once saw that String variables are more efficient than string variables on an earlier version of a book; I also often heard that String is a reference type, string is a value type, and so on. E.g:

string s1 = "Hello,";
string s2 = "world!";
string es3 = s1 + s2; // s3 is "Hello, world!"

This does look like an assignment of a value type. Another example:

string s1 = "a";
string s2 = s1;
s1 = "b"; // s2 is still "a"

Changing the value of s1 has no effect on s2. This makes strings look more like value types. In fact, this is the result of operator overloading. When s1 is changed, .NET reallocates memory for s1 on the managed heap. The purpose of this is to implement a string that is a reference type to a string in normal semantics.

4. Deployment of value types and reference types in memory
I often hear about it, and I often see it in books: value types are deployed on the stack, and reference types are deployed on the managed heap. It's actually not that simple.

MSDN says: All reference types are deployed on the managed heap. It's easy to understand. When creating an application type variable:

object reference = new object ();

The keyword new will allocate memory space on the managed heap and return an address for that memory space. The reference on the left is a reference that stores a memory address; the memory pointed to by this address (located on the managed heap) stores its content (an instance of System.Object). In the following, for convenience, the reference type is deployed on the hosted push.

Look at value types again. The wording in the "C # Language Specification" is "However, unlike classes, structs are value types and do not require heap allocation) on the structure" instead of "Structure allocates memory on the stack". This can be confusing: where are the value types deployed?

4.1 Array
Consider the array:

int [] reference = newint [100];

By definition, arrays are all reference types, so int arrays are of course reference types (that is, reference.GetType (). IsValueType is false).

The elements of the int array are all ints. By definition, int is a value type (that is, reference [i] .GetType (). IsValueType is true). So are the value type elements in the reference type array on the stack or the heap?

If you use WinDbg to see the specific locations of reference [i] in memory, you will find that they are not on the stack, but on the managed heap.

Actually, for arrays:

TestType [] testTypes = new TestType [100];

If TestType is a value type, storage space is allocated for 100 value type elements on the managed heap at one time, and the 100 elements are automatically initialized, and the 100 elements are stored in this memory.

If TestType is a reference type, space will be allocated for testTypes in the managed heap first, and no elements will be automatically initialized at this time (that is, testTypes [i] is null). The storage space of this reference type element will not be allocated on the managed heap until some code is initialized in the future.

4.2 Type Nesting
It is even more confusing when the reference type contains a value type, and when the value type contains a reference type:

public classReferenceTypeClass
{
Private int_valueTypeField;
Public ReferenceTypeClass ()
{{{
_ValueTypeField = 0;
}
Public method ()
{{{
Int valueTypeLocalVariable = 0;
}
}
ReferenceTypeClass referenceTypeClassInstance = new ReferenceTypeClass (); // Where is _valueTypeField?
referenceTypeClassInstance.Method (); // Where is valueTypeLocalVariable?

public structure ValueTypeStruct
{
Private object_referenceTypeField;
Public method ()
{{{
__ReferenceTypeField = new object ();
Object referenceTypeLocalVariable = new object ();
}
}
ValueTypeStruct valueTypeStructInstance = newValueTypeStruct ();
valueTypeStructInstance.Method (); // Where is _referenceTypeField? And where is referenceTypeLocalVariable?

Just looking at valueTypeStructInstance, this is a struct instance, and it seems like the whole block was thrown on the stack. But the field _referenceTypeField is a reference type, and the local variable referenceTypeLocalVarible is also a reference type.

ReferenceTypeClassInstance has the same problem. ReferenceTypeClassInstance itself is a reference type and it seems that it should be deployed on the managed heap in its entirety. But the field _valueTypeField is a value type, and the local variable valueTypeLocalVariable is also a value type. Are they on the stack or the managed heap?

The law is:

Reference types are deployed on the managed heap;
A value type is always allocated where it is declared: when it is a field, it is stored with the variable (instance) to which it belongs; when it is a local variable, it is stored on the stack.
Let's analyze the above code. For reference type instances, referenceTypeClassInstance:

From the context, referenceTypeClassInstance is a local variable, so it is deployed on the managed heap and held by a reference on the stack;
The value type field _valueTypeField is part of the reference type instance referenceTypeClassInstance, so it is deployed on the managed heap following the reference type instance referenceTypeClassInstance (somewhat similar to the case of an array);
valueTypeLocalVariable is a value type local variable, so it is deployed on the stack.
And for value type instances, valueTypeStruct:

According to the context, the value type instance valueTypeStructInstance is a local variable rather than a field, so it is located on the stack;
The reference type field _referenceTypeField does not have the problem of following. It must be deployed on the managed heap and held by a reference (the reference is part of the valueTypeStruct and is located on the stack);
Its reference type local variable referenceTypeLocalVariable is obviously deployed on the managed heap and held by a reference located on the stack.
So, simply saying "value types are stored on the stack and reference types are stored on the managed heap" is not right. It must be analyzed on a case-by-case basis.




5. Identify use cases for value types and reference types

In C #, we use struct / class to declare a type as a value type / reference type. Consider the following example:
SomeType [] oneTypes = new SomeType [100];
If SomeType is a value type, it only needs to be allocated once, and its size is 100 times that of SomeType. If SomeType is a reference type, it needs 100 allocations at the beginning. After the allocation, each element of the array is null, and then 100 elements are initialized. As a result, a total of 101 allocations are required. This will consume more time and cause more memory fragmentation. Therefore, if the responsibility of the type is mainly to store data, the value type is more appropriate.
In general, value types (which do not support polymorphism) are suitable for storing data for C # applications to manipulate, while reference types (which support polymorphism) should be used to define the behavior of the application. Usually we create more reference types than value types. If the following conditions are met, then we should create as a value type:
The main responsibility of this type is for data storage. Zh
The common interface of this type is completely defined by some data member access attributes. Zh
This type can never have subclasses. Zh
This type does not have polymorphic behavior.




5. The difference between value types and reference types (summary)

Same point:
Reference types can implement interfaces, and structures in value types can also implement interfaces;
Both reference and value types inherit from the System.Object class.

1) In terms of scope
C # value types include: structures (numeric types, bool types, user-defined structures), enums, and nullable types.
C # reference types include: arrays, user-defined classes, interfaces, delegates, objects, strings.
2) Memory allocation:

The elements of an array, whether they are reference types or value types, are stored on the managed heap.

A reference type stores a reference on the stack, and its actual storage location is on the managed heap. Referential types are deployed on managed push. The value type is always allocated where it is declared: when it is a field, it is stored with the variable (instance) to which it belongs; when it is a local variable, it is stored on the stack. (The stack memory is automatically released, and the heap memory is automatically released by the GC in .NET)

3) Applicable occasions

Value types have better efficiency in memory management, and do not support polymorphism, which is suitable for use as a carrier for storing data; reference types support polymorphism, which is suitable for defining the behavior of an application.

Reference types can derive new types, while value types cannot, because all value types are sealed;
Reference types can contain null values, and value types cannot (nullable type functions allow null to be assigned to value types, such as int? A = null;);
Assignment of a reference type variable copies only a reference to the object, not the object itself. When you assign a value type variable to another value type variable, the contained value is copied.


It is worth noting that both the reference type and the value type are inherited from the System.Object class. The difference is that almost all reference types inherit directly from System.Object, while value types inherit their subclasses, that is, directly inherit System.ValueType. That is, System.ValueType is itself a class type, not a value type. The key is that ValueType overrides the Equals () method, so that the value types are compared according to the value of the instance, rather than the reference address.


————————————————
Copyright statement: This article is an original article by CSDN blogger "HawkJony", which follows the CC 4.0 BY-SA copyright agreement. Please reprint the original source link and this statement for reprinting.
Original link: https://blog.csdn.net/qiaoquan3/article/details/51202926

Related Article

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.