Struct vs Class in C#

To understand the difference between struct and class in C# you should be familiar that there are two types of memory in the language – Stack and Heap:

  • Stack (static memory) – pre-allocated memory for the program. It keeps its value type variables, call stack, and metadata.
  • Heap (dynamic memory) – Contains everything outside the stack. It is called dynamic because every time our program needs additional memory, it calls to the OS, and the OS provides an additional heap. In the heap are kept the reference types.

In this post, I will explain the difference between struct and class in C#, which is mainly connected with the memory where they are kept.

What is a Structure?

As you may know, classes in C# are reference types. It means that when you create an instance of a class, it is kept in the heap memory (dynamic memory). The pre-allocated static memory in our program keeps only an address to the actual position in the heap.

On the other hand, structures are behaving like value types. They may look like classes but are kept in the static memory. And that’s the main difference between the two types. They are similar to classes, and can have fields, properties, methods, events, and so on, but are kept in the stack. A good example of a struct in C# is the DateTime object.

Because the structure is a value type, it always has value. A structure can’t be null, because it is kept in the stack, not in the heap. For that reason a structure always has a default build-in empty constructor, which gives initial state.

Copying struct vs class

In this paragraph, we will see how copying instances influences different structures and classes. For instance, here is the structure Point:

C#
internal struct Point
{
    public Point(double x, double y, double z)
        :this()
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public double x;
    public double y;
    public double z;
}

This is a struct, defining a simple point in the three-dimensional space. When using a custom constructor, you must inherit the default one to ensure the structure will have a default value. You do that by calling :this(). You don’t need any properties for the example, they are just given for better representation.

Let’s also define a custom class (no properties needed):

C#
internal class CustomClass
{
}

Next, let’s create a Point and assign another point to the same instance. This will copy the first instance to the second one:

C#
Point firstPoint = new Point();
var secondPoint = firstPoint;

The two points are not kept in the stack. Let’s use pointers to retrieve their actual addresses:

C#
Point* firstPointPointer = &firstPoint;
Point* secondPointPointer = &secondPoint;
Console.WriteLine($"First point address: {(int)firstPointPointer}");
Console.WriteLine($"Second point address: {(int)secondPointPointer}");

The result is:

Struct and Class in C#-  Copying structures and comparing their addresses in the stack memory
Copying structures and comparing their addresses in the stack memory

As you can see a different address for the second Point is allocated in the stack. That’s how value types behave – their entire values are copied in another memory block.

This is not the same with the classes, where another address is created in the stack for the new instance, but it actually points to the same reference in the heap. For instance:

C#
var customInstance1 = new CustomClass();
TypedReference reference1 = __makeref(customInstance1);
IntPtr customInstancePointer1 = **(IntPtr**)(&reference1);
Console.WriteLine($"Instance address 1: {customInstancePointer1}");

var customInstance2 = customInstance1;
TypedReference reference2 = __makeref(customInstance2);
IntPtr customInstancePointer2 = **(IntPtr**)(&reference2);
Console.WriteLine($"Instance address 2: {customInstancePointer2}");

In this example, we are using pointers again to retrieve the address in the heap. And the result is:

Struct and Class in C# - Copying classes and comparing their addresses in the heap memory
Copying classes and comparing their addresses in the heap memory

The addresses are the same because the 2 variables point to the same instance in the heap.

When to use structures?

In conclusion, structures are usually used for storing small data, most commonly without behavior. There is no need for class and allocation of the heap memory for a Point object for instance. It has only 3 properties and nothing more. Use structures for simple objects, which can’t be stored in another value type.