Value Type and Reference Type in C#

In this article, we’ll explore the difference between value types and reference types in the C# programming language.

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

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

Value type and reference type in C#
Value type and reference type 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 about value type and reference type in C#:

  • Storage location: –
    • Value Type: Stored on the stack, which is a region of memory that stores temporary variables. Examples include int, float, bool, and struct.
    • Reference Type: Stored on the heap, which is a region of memory that stores objects. Examples include string, array, class, and delegate.
  • Data Containment:
    • Value Type: Directly contains its data. For example, an int variable holds the actual integer value.
    • Reference Type: Contains a reference (pointer) to the data. For example, a string variable holds a reference to the actual string data stored on the heap.
  • Assignment behavior:
    • Value Type: When assigned to another variable, a copy of the value is made. Changes to one variable do not affect the other. For example, if a is 5 and b = a, changing a to 10 does not affect b.
    • Reference Type: When assigned to another variable, the reference is copied. Both variables point to the same data, so changes in one variable affect the other. For example, if a and b are references to the same object, modifying the object through a will reflect in b.
  • Nullable:-
    • Value Type: By default, cannot be null. However, nullable value types (e.g., int?) can be used to represent null values.
    • Reference Type: Can be null, meaning the variable can point to no object.
  • Performance:-
    • Value Type: Generally faster because they are allocated on the stack and do not require garbage collection.
    • Reference Type: Generally slower due to heap allocation and the overhead of garbage collection.
  • Default initialization:
    • Value types like int and float are automatically set to their default values (e.g., 0 for int and 0.0 for float) when created. Reference types, on the other hand, are initialized to null.
  • Memory management: –
    • Value types are stored on the stack and are automatically removed when they go out of scope.
    • Reference types are stored on the heap and need garbage collection to clean up when they’re no longer needed.
  • Namespace: In C#, value types are derived from System.ValueType, while reference types are derived from System.Object.
  • Inheritance: Value types cannot inherit from other classes or structs, but they can implement interfaces. Reference types can inherit from other classes and also implement interfaces.

Examples:


// Value Type:
int a = 10;
float pi = 3.14f;
bool isTrue = true;
struct Point { public int X; public int Y; }

// Reference Type:
string name = "Alice";
int[] numbers = {1, 2, 3};
class Person { public string Name; }
delegate void MyDelegate();

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

  • Value Type
  • Reference Type

Value Type In C#:

In C#, value types are usually stored in stack memory. Each value type has its own copy of the data and stores the actual value in its own memory location, not a reference. Value types inherit from System.ValueType and directly contain their data.

When you create a variable of a value type, it holds the actual value directly. This means each variable of a value type has its own separate copy of the data. For example, if you have two int variables, each one holds its own integer value independently.

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 a heap, and value types are stored in the stack memory. 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 its reference 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 and user-defined structs. When created, these types are automatically initialized to their default value and are automatically removed from memory when they’re no longer needed.

Reference types such as class, interface, array, and string are generally stored in a Heap memory. 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.

It means that both variables point to the same thing in memory, so if you change one, the other changes too.

FAQs:

Q: What is the main difference between value types and reference types in C#?

The main difference between value types and reference types in C# is how they are stored in memory. Value types are stored on the stack, while reference types are stored on the heap.

Q: What are some examples of value types in C#?

Some examples of value types in C# include int, float, double, bool, and struct.

Q: What are some examples of reference types in C#?

Some examples of reference types in C# include class, interface, array, and string.

Q: What is the default initialization value for a value type in C#?

The default initialization value for a value type in C# is typically 0 or null, depending on the data type.

Q: How does assignment behaviour differ for value and reference types in C#?

When you assign a value type to a variable, the value is copied to the new variable. When you assign a reference type to a variable, the reference to the object is copied, not the object itself.

Q: How does the equality comparison between value and reference types in C# differ?

When you compare value types for equality, the comparison is done by value. When you compare reference types for equality, the comparison is done by reference.

Q: Can you convert between value types and reference types in C#?

Yes, you can convert between value and reference types in C# using implicit or explicit conversion.

Q: What are some advantages of using value types in C#?

Some advantages of using value types in C# include faster performance, smaller memory footprint, and no issues with garbage collection.

Q: What are some advantages of using reference types in C#?

Some advantages of using reference types in C# include the ability to store and manipulate large amounts of data, the ability to pass objects between methods and classes, and the ability to create complex data structures.

Q: Which type should you use in my C# program, value or reference types?

The choice between value types and reference types in C# depends on your specific use case and the requirements of your program. In general, value types are preferred for small data types that are frequently used, while reference types are preferred for larger and more complex data types.

Check out these posts too:

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

Shekh Ali
5 2 votes
Article Rating
Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments