Structs (struct vs class)
A struct looks almost identical to a class, but there's one profound difference: a struct is a value type . It's copied when you assign or pass it, instead of shared by reference. Understanding value vs reference semantics is one of the most important things you'll learn in C# — it explains a whole category of "why did that change?!" bugs.
Learn Structs (struct vs class) in our free C# course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.
Part of the free C# course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 Real-World Analogy
Imagine handing a colleague a document. With a class , you share a single Google Doc — they edit it and your copy changes too, because it's the same document. With a struct , you photocopy the document and hand them the copy — they can scribble all over it and your original is untouched. That photocopy-on-handover behaviour is exactly what "value type" means.
1. Declaring a Struct
A struct can hold fields, a constructor, properties and methods — syntactically it's nearly a class. It's ideal for small bundles of data that represent a single value, like a 2D point. The classic example is Point : two coordinates plus a little behaviour.
2. Value vs Reference Semantics
This is the whole point of the lesson. When you assign a struct to a new variable, you get an independent copy — change one and the other is unaffected. When you assign a class , both variables point at the same object — change one and you change "both". Run this side-by-side comparison and let it sink in.
Your turn — complete a temperature struct by writing a computed property.
3. readonly Structs
Mutable structs are a known foot-gun: because they copy so freely, a "change" you make might land on a copy you didn't mean to touch. The modern best practice is to make structs readonly so they're immutable — operations return a new value instead of mutating in place. This removes the surprise entirely.
4. record struct
If you want value-copy semantics and the free value equality, ToString() , and deconstruction of a record, use a record struct . A readonly record struct is the ideal small immutable value type — it's exactly what types like Vector or Color should be.
🧩 Reorder Challenge
These lines build and use a struct, but they're scrambled. Order them so the program compiles and prints the area.
Fields, then constructor, then methods make up the struct body; you must construct r before calling Area() on it.
🧠 Quick Recall
1 — b is a copy, so changing b.N leaves a.N at 1.
5 — a and b reference the same object, so the change is shared.
True — record structs get generated value equality.
struct vs class — Decision Guide
struct
class
Kind
Value type
Reference type
On assignment
Copied
Shared (reference)
Lives on
Stack (usually)
Heap
Can be null
No (unless T?)
Yes
Inheritance
No
Best for
Small immutable values
Objects with identity/behaviour
Pro Tips
- 💡 Default to classes; reach for structs deliberately when you have small, immutable, value-like data.
- 💡 Make structs readonly to avoid the mutable-struct copy bugs entirely.
- 💡 Keep structs small (~16 bytes). Large structs are expensive to copy on every assignment and pass.
- 💡 readonly record struct is the sweet spot for things like points, colours, and money.
Common Errors (and the fix)
- "My change disappeared!" — you mutated a struct that was actually a copy (e.g. an item fetched from a list). Make the struct readonly and return new values.
- "CS0843: auto-property must be fully assigned": a struct constructor must assign every field/auto-property before it finishes.
- Trying to inherit a struct: structs can't inherit. Use composition or an interface instead.
- Big struct, slow code: copying a large struct everywhere hurts performance. If it's big or long-lived, it should probably be a class.
Frequently Asked Questions
Mini-Challenge: an RGB Color Struct
Build a small immutable value type that represents a colour and can print itself as a hex string. This is a textbook real-world use of a readonly struct .
🎉 Lesson Complete
- ✅ Structs are value types — copied on assignment
- ✅ Classes are reference types — shared by reference
- ✅ Copy vs share explains a whole class of "why did that change?" bugs
- ✅ Prefer readonly structs for safe immutability
- ✅ readonly record struct = value copy + value equality
- ✅ Next lesson: Tuples & Deconstruction
Practice quiz
A struct is what kind of type?
- A reference type
- An interface
- A value type
- An abstract type
Answer: A value type. A struct is a value type - copied when assigned or passed - unlike a class, which is a reference type.
What happens when you assign one struct variable to another?
- You get an independent copy
- Both share the same object
- It throws an exception
- The original becomes null
Answer: You get an independent copy. Assigning a struct makes a full copy; changing the copy does not affect the original.
Given 'class C', after var b = a; b.X = 99; what is a.X (where a.X was 1)?
- 1
- 0
- null
- 99
Answer: 99. Classes are reference types - a and b point at the same object, so the change is shared and a.X is 99.
What does declaring a 'readonly struct' guarantee?
- It lives on the heap
- It can't be mutated after creation - every field is readonly
- It can be inherited
- It can be null
Answer: It can't be mutated after creation - every field is readonly. A readonly struct is immutable; operations return a new value instead of mutating in place.
Why are mutable structs discouraged?
- Because structs copy so freely, a 'change' may land on a copy you didn't mean to touch
- They're slower to allocate
- They can't have methods
- They always box
Answer: Because structs copy so freely, a 'change' may land on a copy you didn't mean to touch. Easy copying means mutations can hit an unintended copy; making structs readonly removes the surprise.
What extra features does a 'record struct' add over a plain struct?
- Inheritance support
- Heap allocation
- Generated value equality, ToString(), and deconstruction
- Null support
Answer: Generated value equality, ToString(), and deconstruction. A record struct is still a value type but the compiler generates value equality, ToString(), and deconstruction.
Can a struct inherit from another struct or class?
- Yes, like classes
- No - structs can't be the base for or derive from inheritance
- Only from interfaces' base classes
- Only from abstract structs
Answer: No - structs can't be the base for or derive from inheritance. Structs can implement interfaces and have methods, but they cannot participate in inheritance.
What does a struct constructor have to do before it finishes?
- Call base()
- Return a value
- Mark itself readonly
- Assign every field / auto-property
Answer: Assign every field / auto-property. CS0843 occurs if a struct constructor doesn't fully assign every field/auto-property before completing.
Roughly what size is a struct generally recommended to stay under?
- 1 byte
- 16 bytes
- 256 bytes
- 1 KB
Answer: 16 bytes. Microsoft's guideline is small (~16 bytes), immutable, and short-lived; larger data is expensive to copy.
Can a non-nullable struct variable be null?
- Yes, always
- Only in classes
- No, unless you use a nullable type like T?
- Only when readonly
Answer: No, unless you use a nullable type like T?. Value types can't be null by default; you need a nullable value type (T?) to allow null.
Continue this course
- Previous: Records
- Next: Tuples & Deconstruction