A language tour
Strongly typed, expressively modern โ a language that keeps getting better with every release.
01 โ LINQ
Language Integrated Query lets you write database-style queries directly against in-memory collections, XML, databases, or any data source that implements IEnumerable. It's one of the most influential features in language design history.
"LINQ is a set of features that extends powerful query capabilities to the language syntax of C#. It's the thing other language designers study and wish they'd done."
โ Anders Hejlsberg, designer of C#var products = new[] { new { Name = "Laptop", Price = 999.00m, Category = "Electronics" }, new { Name = "Phone", Price = 699.00m, Category = "Electronics" }, new { Name = "Desk", Price = 350.00m, Category = "Furniture" }, new { Name = "Monitor", Price = 450.00m, Category = "Electronics" }, }; // Query syntax โ reads like SQL, compiles to method calls var expensive = from p in products where p.Category == "Electronics" && p.Price > 600 orderby p.Price descending select p.Name; // Method syntax โ identical result, different style var total = products .Where(p => p.Category == "Electronics") .Sum(p => p.Price); // 2148.00
LINQ works against any IEnumerable<T> โ the same syntax that queries a list of objects can query a database via Entity Framework, producing optimised SQL at runtime.
02 โ async/await
C# pioneered async/await โ a pattern now copied by Python, JavaScript, Rust, Swift, and Kotlin. It lets you write non-blocking I/O without callbacks, without threads, without the inversion of control that makes async code hard to reason about.
using System.Net.Http; using System.Text.Json; public async Task<string> FetchUserNameAsync(int userId) { using var client = new HttpClient(); // Awaiting suspends this method without blocking the thread var json = await client.GetStringAsync( $"https://api.example.com/users/{userId}"); var user = JsonSerializer.Deserialize<User>(json)!; return user.Name; } // Parallel async โ all three requests fire simultaneously var (a, b, c) = await ( FetchUserNameAsync(1), FetchUserNameAsync(2), FetchUserNameAsync(3));
String interpolation with $"..." is a C# feature from 2015, later adopted by many languages. The compiler checks the expression inside {} at compile time.
03 โ Pattern Matching
Modern C# has one of the most powerful pattern matching systems in mainstream languages โ combining type tests, property patterns, and positional patterns into exhaustive, compiler-checked switches.
abstract record Shape; record Circle(double Radius) : Shape; record Rectangle(double W, double H) : Shape; record Triangle(double Base, double Height) : Shape; double Area(Shape s) => s switch { Circle { Radius: > 0 } c => Math.PI * c.Radius * c.Radius, Rectangle { W: var w, H: var h } => w * h, Triangle (var b, var h) => 0.5 * b * h, _ => throw new ArgumentException("Invalid shape") }; Console.WriteLine(Area(new Circle(5))); // 78.54 Console.WriteLine(Area(new Rectangle(3,4))); // 12
The compiler warns if the switch is not exhaustive โ if you add a new Shape subtype and forget to handle it, you get a warning before you ship. Safety by design.
04 โ Records
Records give you value-based equality, with expressions for non-destructive mutation, and concise syntax for data-carrying types. In five characters, you get what took fifty lines in Java.
// One line declares a type with constructor, properties, // Equals, GetHashCode, ToString, and deconstruct record Point(double X, double Y); record Person(string Name, int Age); var alice = new Person("Alice", 30); // "with" creates a modified copy โ original is untouched var olderAlice = alice with { Age = 31 }; // Value equality โ not reference equality var alice2 = new Person("Alice", 30); Console.WriteLine(alice == alice2); // True (not by reference) // Deconstruction var (name, age) = alice; Console.WriteLine($"{name} is {age}"); // Alice is 30
Before records, implementing proper value semantics in C# required overriding Equals, GetHashCode, ==, !=, and adding IEquatable<T>. Records reduce this to a single declaration.
05 โ Nullable Reference Types
C# 8 made reference types non-nullable by default. The compiler tracks nullability through your entire program, turning Tony Hoare's "billion-dollar mistake" into a compile-time warning instead of a runtime crash.
// #nullable enable โ opt in (default in new projects) string name = "Alice"; // cannot be null string? maybeNull = null; // explicitly nullable // Compiler error: maybeNull.Length โ possible null dereference int len = maybeNull?.Length ?? 0; // safe: returns 0 if null // Null-coalescing assignment maybeNull ??= "default"; // The compiler infers non-null after a null check if (maybeNull is not null) Console.WriteLine(maybeNull.ToUpper()); // safe inside block
The ??= null-coalescing assignment reads as "assign only if currently null." It's a small syntactic detail, but it reads as intent โ the code says exactly what it means.
06 โ The Whole Picture
With Span<T>, ref structs, and AOT compilation, C# can match native code in hot paths.
Unity runs on C#. Hundreds of millions of players interact with C# code every day without knowing it.
One of the fastest web frameworks in any language, regularly topping the TechEmpower benchmarks.
Compile-time code generation without runtime reflection โ the next frontier of zero-cost abstraction.
A new language version every year. C# 12 is a different language from C# 1.0 โ and better at every step.
.NET runs on Windows, Linux, macOS, Android, iOS, and WebAssembly. Write once, run anywhere โ and mean it.