Skip to content

C# Structs or Classes?

C# Structs or Classes?
Lost in coding? Discover our Learning Paths!
Lost in coding? Discover our Learning Paths!

C# Structs or Classes? Structs and classes are two of the most commonly used tools for designing software and structuring data. Both structs and classes allow developers to define a set of fields or properties that make up a specific type of data. However, some key differences between structs and classes can impact when and how they should be used.

Structs and Classes Similarities

Structs and classes in C# have several similarities, including:

  • Both can have properties, methods, and constructors.
  • Both can have fields and events.
  • Both can have nested types.
  • Both can implement interfaces.
  • Both can be generic.
  • Both can have access modifiers such as public, private, and protected.
  • Both can have partial implementations.
  • Both can use polymorphism.

Structs and Classes Differences

For example, let’s say you are working on a 2D game and want to create a struct representing a point on the game’s map. You could define the struct in C# like this:

You could then create a point object and assign values to its properties like this:

 

The main difference between structs and classes in C# is that structs are value types and classes are reference types. This means that when a struct is passed to a method, a copy of the struct is passed, whereas, with a class, a reference to the object is passed. This can have important implications for memory usage and performance in certain situations.

In the example above, if I assign the point1 to a new variable named point2


 

And then change the X of the new point:

It doesn’t affect the point1.X to see the result let’s write the X of both variables on the console:
And this is the output:
The original variable is not modified. However, if I define the point as a class:
Then do the same:

 

Guess the output if I log the result.


 

Setting point1.X to 100 updates both point1.X and point2.X :


 

Generally speaking, you can use structs to pass a small amount of lightweight data within a specific scope. They are often used for simple data types such as points, rectangles, or color values. However, classes are generally used for more complex data that must be shared across multiple parts of the program.
Let’s see another example. Imagine that you are creating a social media application and want to create a class representing a user’s profile. The class might include properties such as the user’s name, profile picture, and friends list. You could define the class in C# like this:

Now, if I pass an instance of the UserProfile class to another function, the function receives a reference to the object, not a copy.

Classes are helpful in modeling entities. Entities may contain members (like properties and fields) of struct types. By the way, did you know that we offer a unique and powerful online course that boosts your C# career? Check it out here!

The differences between structs and classes are rooted in how they are allocated in memory. Structs are value types, which means that when a struct is created, it is allocated on the stack. This means that it is only accessible within the scope of the function or block in which it was created. Because structs are on the stack, they are also very fast to access and modify.

On the other hand, classes are reference types, which means that when an object is created, it is allocated on the heap. This means it can be accessed and modified anywhere in the program. Because classes are on the heap, they are slightly slower to access and modify than structs.

Heap vs. Stack

In C#, the heap and the stack are areas of memory used to store data.

The heap is a region of memory used to store objects created dynamically at runtime. It is used to store objects that have a longer lifetime and are accessible by multiple parts of the program. When an object is created on the heap, it remains there until the program ends or the object is explicitly removed by the garbage collector.

On the other hand, the stack is a region of memory used to store local variables, method parameters, and return addresses. It is used to store data that has a short lifetime and is only accessible within the current scope. When a method is called, a new frame is pushed onto the stack, which contains the data for that method. When the method returns, the frame is popped off the stack.

In C#, value types (such as structs) are stored on the stack, while reference types (such as classes) are stored on the heap. This means that when a value type is passed as a parameter to a method or assigned to a variable, a copy of the value is created, while a reference to the object is passed or assigned when a reference type is used.

It’s important to note that since the heap is shared among all threads, it is not thread-safe. If multiple threads are using the heap, accessing the heap’s data can be managed by synchronization mechanisms such as locks, semaphores, and atomic operations to avoid race conditions.

 

Here are some key differences between the heap and stack in C#:

Heap

  • Is a region of memory used to store objects that are created dynamically at runtime.
  • Objects have a longer lifetime and are accessible by multiple parts of the program.
  • Objects remain in the heap until they are explicitly removed or until the program ends.
  • Reference types are stored on the heap.
  • Heaps are not thread-safe and need a synchronization mechanism to avoid possible race.

Stack

  • Is a region of memory used to store local variables, method parameters, and return addresses
  • Data has a short lifetime and is only accessible by the current scope
  • When a method is called, a new frame is pushed onto the stack, and when the method returns, the frame is popped off the tack
  • Value types are stored on the stack.
  • thread-safe because each thread has its own stack.

Remember that the heap and stack are both managed by the runtime, and the programmer does not have direct control over when memory is allocated or freed in either region.

Reference Types vs Value Types

Classes are reference types; structs are value types. This table shows the difference between value types and reference types.

Subject Reference Types (like Classes) Value Types (like Structs)
Allocation Method Allocated on the heap Allocated on 

  • Stacks
  • Or inline in the containing types
Deallocation Method Garbage collected Deallocated when

  • The stack unwinds
  • Or the containing type gets deallocated
Allocation Cost Expensive allocation and deallocation Cheaper allocation and deallocation
Arrays Out-of-Line Arrays (An array of a reference type is a set of references to the instances of the reference types residing on the heap) Inline Array (array of a value type is a set of actual instances of the array)
Boxing Boxing won’t happen in reference types because reference types are cast A value type is boxed when it is cast to a reference type (or an interface the value type implements), and it gets unboxed when it’s cast back to the value type.
Boxing Cost No Boxing Boxes are new objects that are allocated on the heap and garbage-collected. So too much boxing and unboxing can impact the heap, the garbage collector, and the application’s performance negatively. 
Assignments Assignments copy the reference Assignments copy the entire value

Assigning large reference types is cheaper than large value types.

Passing passed by reference A copy of the value is  passed 
Returning The reference is returned A copy of the value is returned 
Changing Changing an instance affects all references pointing to the instance. So changing an instance doesn’t affect any of the copies. Because instances are passed by a copy of the value.
Mutability Reference-type instances are globally mutable in the application Value-type instances are only mutable within the scope in which they resist
Use Cases The majority of the time Consider using value types when the instances are small, commonly short-lived, or commonly embedded in other objects. Only use value types if all of the following are true about the type:

  • The type logically represents a single value, similar to primitive types (int, double, etc)
  • The type is immutable (within the scope)
  • The type doesn’t have to be boxed frequently

When to Choose Structs Over Classes

There are no rules. but in general, consider using structs in the following situations.

  • When you need a simple, lightweight data structure that will be used only within a specific scope.
  • When you must ensure that data remains consistent within the scope and cannot be accidentally modified by another part of the program.
  • When working with logically small data types, like points, rectangles, or color values.

When to Choose Classes Over Structs

Likewise, are no rules. but in general, consider using classes in the following situations.

  • When you need a more complex data structure.
  • When you need to share the data structure across multiple parts of the application.
  • When you want to pass larger, more complex data types around and share them with the clients.

 

Conclusion

Structs and classes are both tools for designing software and structuring data. However, they have different characteristics and are best suited for different use cases. Accessing structs is generally faster, but structs have less functionality than classes. The choice between them should be based on the application’s specific needs. Structs are best used for small data structures and only used (read/written) within a specific scope. At the same time, classes are better suited for more complex data structures that require additional functionality and must be shared across the application.

Multiple variables of a class type can refer to the same object. Meaning that all of the variables refer to the same memory area. In contrast, struct variables are copies. Changing a struct variable is always isolated from changes to other variables and never affects any other copy. This can be useful when you need to ensure that data remains consistent and cannot be accidentally modified by another part of the application.

Lost in coding? Discover our Learning Paths!
Lost in coding? Discover our Learning Paths!
Enter your email and we will send you the PDF guide:
Enter your email and we will send you the PDF guide