SyntaxStudy
Sign Up
C# C# Type System Overview
C# Beginner 1 min read

C# Type System Overview

C# has a unified type system rooted at System.Object. Types are divided into value types (structs, enums, and primitives like int and bool) and reference types (classes, interfaces, delegates, and strings). Value types live on the stack or inline in their containing object; reference types allocate on the heap and are accessed through references. Nullable reference types, enabled via `enable` in the project file, make the compiler warn when a reference-typed variable might be null without an explicit check. Appending `?` to a type name (e.g. `string?`) explicitly marks it as nullable. This dramatically reduces null-reference exceptions at run time. Type inference with `var` lets the compiler deduce the type from the right-hand side of an assignment. The variable is still statically typed; `var` is just syntactic sugar. C# 10 introduced global usings and implicit usings to cut down repetitive `using` directives at the top of every file.
Example
// Demonstrating value types, reference types, and nullable reference types

// --- Value types ---
int    count    = 42;
double pi       = 3.14159;
bool   isActive = true;
char   grade    = 'A';

// Struct: value-type semantics (copied on assignment)
var point1 = new System.Drawing.Point(10, 20);
var point2 = point1;   // independent copy
point2.X = 99;
Console.WriteLine($"point1.X = {point1.X}"); // still 10

// --- Reference types ---
var list1 = new List<int> { 1, 2, 3 };
var list2 = list1;     // same reference
list2.Add(4);
Console.WriteLine($"list1.Count = {list1.Count}"); // 4 (shared object)

// --- Nullable value types ---
int? maybeNull = null;
Console.WriteLine(maybeNull.HasValue);          // False
Console.WriteLine(maybeNull.GetValueOrDefault()); // 0

// --- Nullable reference types (requires <Nullable>enable</Nullable>) ---
string? nullableStr = null;
int length = nullableStr?.Length ?? 0;          // null-conditional + null-coalescing
Console.WriteLine($"Length: {length}");

// --- Type checking ---
object obj = "hello";
if (obj is string s)
    Console.WriteLine($"String of length {s.Length}");

// --- Boxing and unboxing ---
int   num    = 7;
object boxed = num;        // boxing
int   unboxed = (int)boxed; // unboxing
Console.WriteLine(unboxed);