C# Struct: Everything you need to know

A thumbnail showing code. Everything you need to know about C# Timer class.

Have you ever used a struct in C#?

Think again. Int, bool and DateTime are all structs.

So what are structs and how can we use them in our code?

C# struct is a simple data structure. Structs allow us to group pieces into a single unit. The structure value type that we create are light and they don't have complex logic.

The name says it all struct, or structures, offers a way to structure our data, not to define behavior. That's a job for classes.

So it's a good practice to avoid bunch of logic and variables inside a struct. We'll see why in the rest of this article.

Before you use structs, you should know that structs:

  • Are value types
  • Do not support inheritance
  • Can implement interfaces
  • Are stack-allocated
  • Cannot be null

Struct Usage

Definition

To define a custom structure declaration in C#, we use the struct keyword:

csharp
public struct Color 
{
	 public string Name;
}

We can break the above code to:

  • public access modifier
  • struct keyword to define it's a structure
  • Color the struct name
  • public string Name - structure member

Initialization

To initialize a struct, we use the new operator:

csharp
var blue = new Color() { Name = "Blue" };

Access

To access struct members, we use the dot . operator:

csharp
Console.WriteLine(blue.Name);

New keyword

We can also define structs without thenew keyword, like this:

csharp
Color c;
c.Name = "Blue";

If you do not use new, the fields will remain unassigned and you'll get the compiler error.

Default values

If we don't change the values, the default value for structs is the same as the default value for each field inside the struct.

If we have a struct defined as:

csharp
var blue = new Color();

The default value of the field Name will be default(string) which is null.

When to use structs?

Structs store data. Classes define behavior.

Structs are ideal for simple structures or data carriers.

These questions will help you decide whether to use a struct:

  1. What is the primary responsibility of this type? Is it data storage?
  2. Is its public interface defined entirely by properties that access or modify its data members?
  3. Will this type ever have subclasses?
  4. Will this type need polymorphism?

Struct vs Class

The main difference between struct and class in C# is that structs are value types, while classes are reference types. Classes support inheritance, but structs don't. Classes can have a null reference, while structs can't.

This table summarizes the differences between structs and classes:

ClassesStructs
Reference typeValue type
Support inheritanceNo inheritance
Can have null referenceCannot have null reference
Contain complex logicLight on logic, they structure data
Can have parameterless constructorsCan have parameterless constructors

Struct vs Record

The main difference between struct and record is that struct is a value types, while record is an immutable object. Structs are better for structure that is similar to primitive data types such as int, bool, and double. On the other hand, records encapsulate complex data.

Reference type vs value type

In C#, you use the struct and class keywords to declare whether a new type should be a value type or a reference type.

Value types are small and lightweight, while reference types form class hierarchy. The lightweight makes types more efficient in terms of memory and CPU usage.

When we pass a value type to a method, the instance of that value type is copied. Reference types are passed by reference, so they are not copied.

Read-only structs

A readonly struct ensures that all fields are readonly. This makes it easier to declare intent, and also allows the compiler more optimization freedom.

Read-only structs are a great way to prevent defensive copying. They give developers more confidence that data won’t change.

Struct modifiers

Structs support the same modifiers as classes. These are:

  • new
  • public
  • protected
  • internal
  • private
  • unsafe_modifier

Structs in C# should be designed to be immutable, which means they cannot change their internal state after they have been created.

Can structs implement interfaces?

Structs can implement interfaces. The C# community rarely recommends it because it makes boxing more likely.

From my experience, I think of structs as a very specific group of data. So having different implementations isn't very useful.

Default parameterless constructor

Starting C# 10.0, structs can have parameterless constructors.

That means we can define our defaults in one place. For example:

csharp
public struct Color
{
	public string Name;	
	public Color()
	{
		Name = "N/A";
	}
}

Parameterless constructors are a much cleaner way to write code because all our values are in one place.

Before C# 10.0, parameterless constructors didn't work. We would get a compile-time error:

error CS0568: Structs cannot contain explicit parameterless constructors

Boxing

Converting a struct to an interface causes boxing.

In C#, boxing is converting a value type to an interface that this value type implements.

When we box a value, it creates a new object on the heap and copies the value into it. The new allocation might lead to performance degradation. So if you decide to use interfaces with structs, pay attention to boxing.

C# Boxing of a struct
Example of boxing in the Intermediate Language (IL) when we box a struct.

Struct performance

Adam Sitnik from Microsoft ran a series of tests to compare the performance of value types and reference types.

When you pass a value type to or from a method, the copy is made every time. The more fields the struct has, the more expensive copying becomes.

The ref keyword for the rescue.

To improve performance of structs we can pass them by reference using the ref keyword. That way, when we pass a struct to a method, we pass a reference rather than a copy.

Downsides of structs

The two main downsides of structs are hierarchies and performance.

  • Structs do not support inheritance. It’s a common object-oriented techniques that classes support. So we cannot create hierarchies of value types using structs.
  • If we pass the struct between methods, data gets copied. It might not seem much, but we can easily get in trouble if we have a large list of structs.

Use cases

The most common use for structures is simple grouping of data. The best example of it is the native implementation of .NET libraries.

Head over to the .NET Framework reference source. There’s a lot to learn.

For example, the nullable wrapper is also a struct.

Structs don’t support null by default, but they do with the nullable wrapper. If you want to see how all that works, check out my article on C# nullable.

C# Nullable struct
Source code for the Nullable struct.

Another great example is the DateTime struct. It has a lot of data manipulation and it’s interesting to see how they’ve used struct members to organize date representation.

Conclusion

Like many other programming languages, C# supports both value types and reference types.

A class is a reference type that is simply a reference to an object on the heap, while structs are value types.

Structs are great for simple data structures.

The key points of this article are:

  • The struct object passed around is copied, changing any properties of the original object does not affect the copies.
  • Structs are useful for representing small pieces of data.
  • When designing your own types, be sure to consider if their functionality fits better in a struct or class structure.
  • Having default parameterless constructor for structs in C# 10.0 makes it much easier to define types without repeating code.
  • ref modifier is used for passing references to value types to improve performance.
  • Unlike classes, structs cannot be inherited.
Published on