Value Type and Reference Type in C#

In this article, we’ll look at the difference between a value type and a reference type in the C# programming language.

C# is a strongly-typed language, which means that every variable has a specific type that determines the values it can store and the operations it can perform. There are two main categories of types in C#: value types and reference types.

The diagram below illustrates the different data types in C#.

Value type and reference type in C#
Data types in C#

Comparison Table: C# value type and reference type

The following is a summary of the main differences between value types and reference types in C#:

CharacteristicC# Value TypesC# Reference Types
Storage location:Stack memoryHeap memory
Default initialization:0 or nullnull
Assignment behavior:Copies valueCopies reference
Equality comparison:By ValueBy reference
Conversion between types:Implicit or explicitImplicit or explicit
Examples:int, float, bool, structclass, interface, array, string

Difference between value type and reference type in C#

Here is a more detailed explanation of each characteristic:

  • Storage location: Value types are stored directly in the stack, which is the memory used for holding local variables and function parameters. Reference types, on the other hand, are stored in the heap, which is where dynamically-allocated objects are kept.
  • Default initialization: Value types are automatically initialized to their default value when they are created. For example, an int is initialized to 0 and a float is initialized to 0.0. Reference types are automatically initialized to null when they are created.
  • Assignment behavior: When we assign a value type to another value type, the value is copied directly from one variable to the other. But when we do the same thing with reference types, it only copies the reference and not the actual object.
  • Equality comparison: When we compare two value types using ==, it compares the actual values. But when we compare two reference types, it only compares the reference to the object. So, two reference variables are only considered equal if they refer to the same object in memory.
  • Conversion between types: We can convert a value type to another value type using either implicit or explicit type conversions. Implicit conversions are performed automatically by the compiler, while explicit conversions require a typecast. Reference types can also be converted using either implicit or explicit type conversions, but these conversions are usually more limited.
  • Memory management: Value types are automatically removed from the stack memory when they go out of scope, while reference types require the use of a garbage collector to be removed from the heap.
  • Namespace: In C#, value types are derived from the System.ValueType class, while reference types are derived from the System.Object class.
  • Inheritance: In C#, value types are not allowed to inherit from any other class or struct, with the exception of interfaces. On the other hand, reference types can be inherited from other classes or interfaces.
  • Examples: Common examples of value types in C# are: int, float, bool, and struct. Common examples of reference types are: class, interface, array, and string.

The two main categories of C# types are as follows.

  • Value Type
  • Reference Type

Value Type In C#

In C#, Value types are generally stored in the stack memory, while reference types are kept in the managed heap. A value type is a type that inherits from System.ValueType and stores data in its own memory allocation.

  • In another way, each variable, object, and value type has its own copy of the data.
  • In C#, a value type does not carry a reference; instead, it stores the actual value in its own stack memory location. This means that these data types’ variables directly contain values.

Types of value types in C#:

  • Built-in value types in C#
  • User-defined value type in C#

01. int, long, float, double, byte, decimal, char, bool, and short are a few examples of Built-in value types.

02. struct and enum are examples of user-defined value types.

Example: Value type in C#

The following is an example of a value type in C#.

using System;
class Program
{
    static void Main()
    { 
        // Here, integer x and y variables are value types
        int x = 100;
        int y  =  x;
        // increment y by 1
            y++; 
      
        Console.WriteLine($"x = {x} y = {y}");
        Console.ReadLine();
    }
    // Output: x = 100 y = 101
}

Once we run the program, we will get the following result:

Value type output
The output of the above program.

Here, both the variable x and y will be present on the stack memory, but as separate entities.

Reference Type in C#

All the reference types in C# are derived from System.Object class.

A reference type carries a pointer to the location in memory where the actual data is stored, rather than storing the data itself. This data is stored on the managed heap, while the reference to the data is stored on the stack.

When we assign a reference type variable to another variable, it creates a new reference to the same data instead of making a new copy of the data.

Two reference type variables can refer to the same object in the heap. This means that any changes made to the object through one variable will also be seen in the other variable because both variables are pointing to the same object in memory, not each having its own copy of the object.

The following are two types of reference types in C#:

  • Built-in reference types
  • User-defined reference types

01. Built-in reference type in C#:   object ,  string ,  dynamic 

02. User-defined reference type in C#:  Class ,  Interface ,  Array ,  delegate 

Example: Reference type in C#

Let’s understand the reference type by using the following example.

using System;
namespace ReferenceType
{
    // Here, the 'User 'class is a reference type
    class User
    {
        // public field
        public int age = 10;
    }
    class Program
    {
        static void Main(string[] args)
        {
          // Creating object of the 'User' class.
            User user1 = new User();

          // Assign object user1 to the new object user2
            User user2 = user1;

          // Print the value of object user1 and user2
            Console.WriteLine($"user1.age = {user1.age} user2.age ={user2.age}");

          //Changed value of user2 object
            user2.age = 20;

          // Print the value of object user1 and user2
            Console.WriteLine($"user1.age = {user1.age} user2.age ={user2.age}");
        }
    }
}

Let’s execute the above program and see the result.

Reference type output
The output of the above program.

We can see in the above result that changing the value of User2 by 20 also changes the value of User1.
Both objects, of course, point to the same memory region in the managed heap.

Understanding Value type in C#

In C#, a value type does not carry a reference; instead, it stores the actual value in its own stack memory.
For example, If we assign a value to the integer variable int x = 100, the value 100 will be stored in the same memory area as variable x.

Value type memory allocation
Memory allocation of a value type in stack memory.

In C#, when you create a value-type variable, it gets its own copy of the data. This means that if you change the value of one variable, the original variable stays the same. The only exception to this is if you pass the variable as an “in”, “ref”, or “out” parameter.

If we create a second int variable y and assign the value of the first variable x to it, the value of x will be copied to y. The Common Language Runtime (CLR) will then allocate two separate memory locations in the stack for x and y, each of which holds the value of 100 and is independent of the other.

Value types assigning values.

If we increase the value of the variable y by one, the value of x will remain unchanged because each variable has its own memory allocation. This means that changes to one variable do not affect the other. In C#, variables with this behavior are called value types.

For example:

Value types memory allocation
Value types memory allocation

In the above example, the value of x remains unchanged after y is incremented by one. This is because x and y are stored in separate memory locations in the stack and do not affect each other. As a result, the value of x remains the same.

Is it true that value types in C# are always saved in stack memory?

It is a common misconception that value types in C# are always stored in stack memory. However, this is not always the case. If a value type variable is a temporary or local variable, or if it is used directly inside a method, it will be allocated on the stack. If a value type variable is declared at the class level or within another reference type, however, it will be stored in the memory.

When a value type variable is no longer in scope, it is automatically freed from memory and the garbage collector has no role in releasing the memory.

Note: There is an exception to the rule that reference types are stored in the heap and value types are stored in the stack. The string type is a reference type, but because it is immutable (i.e., its value cannot be modified), it behaves like a value type. When a string is concatenated or updated, a new string object with the modified value is created in the managed heap. However, the original string object is not modified, and the reference to it remains unchanged.

You can learn more here: Difference between String and StringBuilder in C#

Reference MSDN: Value types, Reference types

Summary:

In C#, there are two main data types: Value types and Reference types. Value types are stored directly in stack memory and include basic types such as int, float, and bool, as well as user-defined structs. These types are automatically initialized to their default value when created and are automatically removed from memory when they’re not needed anymore.

Reference types are generally stored in a Heap memory such as class, interface, array, and string. When these data types are created, by default they are initialized to null and removed by the garbage collector from memory when they are no longer required. When you assign one of these variables to another variable, it copies the address of the first variable, not the actual data. This means that both variables point to the same thing in memory, so if you change one, the other one changes too.

Recommended Articles:

I hope this post was helpful. If you have any questions, please feel free to leave them in the comments section below.

5 1 vote
Article Rating
Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Md Ansar
Md Ansar
2 years ago

Nice Article…..