█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/C# and .NET/C# Type System: Value vs Reference Types
45 minIntermediate

C# Type System: Value vs Reference Types

After this lesson, you will be able to: Distinguish value types vs reference types, use structs, enums, and the null-conditional + null-coalescing operators.

C#'s type system is its superpower, and its trap. Get value vs reference, nullable annotations, and the modern null operators down or you'll write subtly broken code.

Prerequisites:OOP in C#

Value types vs reference types

Value types: int, double, bool, struct, enum, DateTime. Stored inline; copied on assignment. Reference types: class, string, array, delegate, interface. Stored on heap; reference (pointer) copied on assignment. Rule: assignment of a value type COPIES; assignment of a reference type SHARES.

Structs vs classes

Structs = value type with members. Use for small data with no identity.

tsx
// Struct, value type. Allocated on stack (usually). Copied on assignment.
public readonly struct Point {
public double X { get; init; }
public double Y { get; init; }
public Point(double x, double y) { X = x; Y = y; }
public double DistanceTo(Point other) {
var dx = X - other.X;
var dy = Y - other.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
}
var p1 = new Point(0, 0);
var p2 = p1; // COPY, p2 is independent
// Rules of thumb:
// - Struct if: <= 16 bytes, immutable, no identity, mostly read
// - Class if: anything else (the default)
// - readonly struct: enforces immutability + perf

Enums

Type-safe named constants.

tsx
public enum OrderStatus {
Pending, // 0 by default
Confirmed, // 1
Shipped, // 2
Delivered, // 3
Cancelled, // 4
}
var status = OrderStatus.Pending;
if (status == OrderStatus.Pending) { /* ... */ }
// Switch on enum
var message = status switch {
OrderStatus.Pending => "awaiting payment",
OrderStatus.Confirmed => "thanks for ordering",
OrderStatus.Shipped => "on its way",
OrderStatus.Delivered => "enjoy",
OrderStatus.Cancelled => "refunded",
_ => "unknown",
};
// Flags enum (bitfield)
[Flags]
public enum Permissions {
None = 0,
Read = 1,
Write = 2,
Execute = 4,
All = Read | Write | Execute,
}
var perms = Permissions.Read | Permissions.Write;
bool canRead = perms.HasFlag(Permissions.Read); // true

Nullable + null operators

Modern C# defaults to non-nullable references. Use the ? operators when null is possible.

tsx
string? maybe = GetMaybeString(); // can be null
string? name = maybe?.Trim(); // null-conditional: name = null if maybe is null
int? length = maybe?.Length; // length = null if maybe is null
// Null-coalescing: provide a default
string safeName = maybe ?? "anonymous";
// Null-coalescing assignment
string? cached = null;
cached ??= ComputeExpensive(); // assigns only if cached is null
// Null-forgiving (!), tell compiler 'I know it's not null here'
string forced = maybe!; // ignores null warning, crashes at runtime if wrong
// In project file, enable nullable for the whole project:
// <Nullable>enable</Nullable>

⚠️ Nullable annotations are your friend

C# 8 added nullable reference types. Default in new projects. Compiler tracks which references might be null and warns when you might dereference null. Catches the NullReferenceException family at compile time, before they ship. Resist the urge to slap `!` on every warning, that defeats the safety. Fix the actual null source.

Common mistakes

Treating struct like a class (passing big structs by value = perf hit). Mutable structs (notorious bug source, copies have stale state). Suppressing nullable warnings with `!` instead of fixing the null source. Comparing enums with ints (use the enum names, type-safe).

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←OOP in C#
Back to C# and .NET
Collections and LINQ→