C# and .NET Modern Features

Modern C# features (C# 8-12) and .NET capabilities: nullable reference types, records, pattern matching, LINQ, async streams, minimal APIs.

The data

Features

NameVersionDescriptionExampleNotes
Nullable Reference TypesC# 8.0 / .NET Core 3.0Compiler warnings for potential NullReferenceException: string? means nullable, string means non-nullablestring? middleName = null; string firstName = middleName ?? "Unknown";Enable with <Nullable>enable</Nullable> in .csproj
RecordsC# 9.0 / .NET 5Immutable reference types with value equality, positional syntax, with-expressions for non-mutating updatespublic record Person(string FirstName, string LastName); var p2 = p1 with { LastName = "Smith" };Use record class for reference semantics, record struct for value semantics
Pattern MatchingC# 8-12Type patterns, property patterns, relational patterns, list patterns for expressive conditional logicreturn shape switch { Circle c => c.Radius * c.Radius * Math.PI, Rectangle r => r.Width * r.Height, _ => 0 };Evolves each version: C# 7 (is/switch), C# 8 (property/recursive), C# 10 (extended), C# 12 (list)
LINQC# 3.0 / .NET Framework 3.5Language Integrated Query: declarative data querying with deferred execution, query syntax and method syntaxvar adults = people.Where(p => p.Age >= 18).Select(p => p.Name).OrderBy(n => n);Works with any IEnumerable<T>; IQueryable<T> for remote execution (EF Core, SQL)
Async StreamsC# 8.0 / .NET Core 3.0IAsyncEnumerable<T> for asynchronous iteration over sequences, await foreachawait foreach (var item in GetItemsAsync()) { Process(item); }Essential for paginated APIs, database queries, real-time data streams
Minimal APIs.NET 6Simplified HTTP API building without controllers: app.MapGet("/", () => "Hello")var app = WebApplication.Create(args); app.MapGet("/todos/{id}", (int id, TodoDb db) => db.Todos.FindAsync(id));Reduces boilerplate for small APIs; use for microservices, prototypes, simple backends
Primary ConstructorsC# 12 / .NET 8Constructor parameters directly on class/struct declaration, accessible as instance fieldspublic class Person(string firstName, string lastName) { public string FullName => $"{firstName} {lastName}"; }Reduces boilerplate; parameters are in scope for the entire class body
Source Generators.NET 5 / Roslyn 3.8Compile-time code generation: analyze syntax trees and emit new C# source files[GenerateSerializer] public class MyData { } // Generates serialization code at compile timeUsed by System.Text.Json, EF Core, gRPC; eliminates runtime reflection overhead

Fetch the same bytes

The static files are identical to what the API returns, but with no rate limit and no server round trip. Use the API when you want a query and a content type; use the files when you want to cache one document.

curl "https://yjtoon.com/api/dataset/csharp-dotnet-features?format=toon"
const res = await fetch(
  "https://yjtoon.com/static-data/dataset/csharp-dotnet-features.toon"
);
const toon = await res.text();

Rate limit: 120 requests per minute per IP, no key and no signup. API reference →

Topics

  • csharp
  • dotnet
  • nullable-reference-types
  • records
  • pattern-matching
  • linq
  • async-streams