C# — Reference

Source: https://learn.microsoft.com/en-us/dotnet/csharp/

C

  • Created: 2000 by Anders Hejlsberg at Microsoft; standardized as ECMA-334 / ISO/IEC 23270
  • Latest stable: C# 14 with .NET 10 (LTS, Nov 2025); C# 15 in preview with .NET 11 (as of 2026-05)
  • Paradigms: multi-paradigm — object-oriented, component, functional, declarative (LINQ), generic, async, pattern-oriented
  • Typing: static, strong, nominal, with local type inference (var); nullable reference types
  • Memory: GC (generational tracing); Span<T>/ref struct for stack allocation; unsafe/fixed for raw pointers
  • Compilation: compiled to CIL/MSIL, then JIT (RyuJIT) at runtime; NativeAOT for AOT to native binary; tiered compilation + on-stack-replacement
  • Primary domains: enterprise/business apps, web (ASP.NET Core), cloud services, games (Unity), desktop (WPF/WinForms/MAUI), Azure functions, IoT
  • Official docs: https://learn.microsoft.com/en-us/dotnet/csharp/

1. At a glance

  • Owned by .NET Foundation with development led by Microsoft. Roslyn is the open-source compiler.
  • Single cross-platform runtime: .NET (formerly .NET Core; unified since .NET 5). LTS releases on even-numbered .NET versions (.NET 6, 8, 10), STS on odd.
  • C# 15 ships with .NET 11 (preview as of 2026-05); adds collection-expression arguments and union types.
  • C# 14 / .NET 10 is current LTS.
  • Cross-platform: Windows, Linux, macOS, iOS, Android, WebAssembly (Blazor), and embedded (NativeAOT).

2. Getting started

  • Install: Download .NET SDK from https://dotnet.microsoft.com/download (includes runtime + compiler + CLI). Linux: apt install dotnet-sdk-10.0. macOS: brew install --cask dotnet-sdk. Windows: winget install Microsoft.DotNet.SDK.10.

  • Version manager: dotnet SDK supports global.json to pin SDK per repo. Multiple SDKs co-install; CLI selects per global.json.

  • Hello, world (top-level statements, C# 9+):

    Console.WriteLine("Hello, world!");

    Run: dotnet new console -n hello && cd hello && dotnet run.

  • Project layout: MyApp.csproj + Program.cs; SDK-style projects (<Project Sdk="Microsoft.NET.Sdk">). Solutions (.sln) group projects.

  • Build / package: dotnet CLI (build, run, test, publish, pack); MSBuild under the hood. Packages from NuGet (https://nuget.org).

  • REPL: dotnet-script, C# Interactive (in Visual Studio), Polyglot Notebooks (Jupyter via .NET Interactive). SharpLab (https://sharplab.io) for compiler IL/asm exploration.

3. Basics

  • Primitives: bool, byte/sbyte, short/ushort, int/uint, long/ulong, nint/nuint, float, double, decimal, char, string. Literals: 0x, 0b, _ digit separators (1_000_000), suffixes L, U, M (decimal), f/d.
  • Variables: var x = 1; (inferred), const, readonly, static. Nullable annotations: string? vs string. Block scope, no shadowing within scope.
  • Control flow: if/else, switch statement, switch expression with patterns (x switch { > 0 => "+", _ => "0/-" }), for, foreach, while, do-while, goto. Pattern matching: type, property, list, relational, logical patterns.
  • Functions: static methods, instance methods, local functions, lambdas (x, y) => x + y, expression-bodied members int Square(int x) => x * x;. Optional/named args, params, ref/out/in, ref returns. Delegates (Func<>/Action<>) are first-class.
  • Strings: immutable string. Interpolation: $"Hello {name}". Verbatim: @"C:\path". Raw string literals (C# 11): """...""" with optional interpolation $$"""...""". UTF-8 string literals: "abc"u8.
  • Collections: T[], List<T>, Dictionary<K,V>, HashSet<T>, Queue<T>, Stack<T>, LinkedList<T>, immutable variants (ImmutableArray<T> etc.), Span<T>/ReadOnlySpan<T>, Memory<T>. Collection expressions (C# 12): int[] x = [1, 2, 3];.

4. Intermediate

  • Generics: type parameters on classes/methods/interfaces, constraints (where T : class, IComparable<T>, new()), variance (in/out), default literal default(T), static abstract members in interfaces (C# 11) which enables generic math.
  • Modules/packages: assemblies (.dll); namespaces (namespace Foo.Bar; file-scoped C# 10); NuGet packages distribute compiled assemblies. global using directives.
  • Error handling: exceptions (try/catch/finally/when), no checked exceptions. IExceptionHandler in ASP.NET Core. Pattern: throw on exceptional, return Result/Option types via libraries (LanguageExt, OneOf) or bool TryX(out T) for hot paths.
  • Concurrency: Tasks (Task/Task<T>) with async/await. ValueTask<T> for hot paths. TPL Dataflow, Channels (System.Threading.Channels), IAsyncEnumerable<T> + await foreach. Threads (Thread), ThreadPool, SemaphoreSlim, Interlocked, lock (Monitor). PLINQ, Parallel.ForEach/Parallel.ForEachAsync.
  • I/O & networking: System.IO (File, Stream, FileStream), System.IO.Pipelines (high-perf), HttpClient (and IHttpClientFactory), System.Net.Sockets, System.Net.WebSockets, gRPC.Net.
  • Stdlib highlights: LINQ (System.Linq), System.Text.Json (default serializer; source-generated since .NET 7), Regex (with source generation), DateTime/DateTimeOffset/DateOnly/TimeOnly, TimeProvider (DI-friendly time), Random.Shared.

5. Advanced

  • Memory & GC: generational (gen 0/1/2 + LOH + POH), workstation vs server GC (<ServerGarbageCollection>), background GC, regions (.NET 7+) replace segments. Tuning via DOTNET_GCHeapCount, DOTNET_gcServer, DOTNET_GCConserveMemory. Span<T>/ref struct stack-only types avoid allocations. ArrayPool<T>.Shared for buffer reuse. IDisposable + using for unmanaged resources.
  • Concurrency deep dive: sync context vs ConfigureAwait(false), async state machine (compiler rewrites methods into IAsyncStateMachine), Task continuations, ValueTask reuse via IValueTaskSource, lock-free with Interlocked/Volatile, MemoryBarrier.
  • FFI/interop: P/Invoke ([DllImport] and source-generated [LibraryImport] since .NET 7), COM interop, C++/CLI bridge, DllImportResolver, fixed-size buffers in unsafe structs, Marshal class. C++ via WinRT/CsWinRT.
  • Reflection: System.Reflection, Type.GetType(), Activator.CreateInstance, attributes; DynamicMethod, Reflection.Emit, System.Linq.Expressions (compiled lambdas). Heavy reflection is incompatible with NativeAOT; use source generators instead.
  • Performance tooling: dotnet-trace, dotnet-counters, dotnet-dump, PerfView (Windows), BenchmarkDotNet (the standard for microbenchmarks), dotMemory/dotTrace (JetBrains), Visual Studio Profiler, EventPipe + OpenTelemetry. CrossGen2 AOT pre-JIT, R2R (ReadyToRun), ILVerify.

6. God mode

  • Source generators (Roslyn): compile-time codegen via IIncrementalGenerator. Used by System.Text.Json, LoggerMessage, Regex, LibraryImport, AOT serialization. Replaces runtime reflection in hot paths.
  • Roslyn analyzers + code fixes: ship custom diagnostics + auto-fixes as NuGet packages.
  • Expression trees: Expression<Func<T, bool>> is data, not code; LINQ providers (EF Core, IQueryable) parse and translate. Compile to delegates with .Compile() or interpret manually.
  • Span<T> / ref struct / ref fields / scoped refs: stack-only types, ref returns, ref readonly, scoped keyword (C# 11) for lifetime control. Critical to high-perf APIs (Utf8JsonReader, SpanReader).
  • unsafe + fixed + pointers + stackalloc: raw memory, function pointers (delegate*<int, int>), pinning managed memory.
  • NativeAOT: <PublishAot>true</PublishAot> produces a single native binary, no runtime JIT, no MSIL — but trims reflection/dynamic codegen. Requires source generators + trimming-friendly code.
  • Channels + IAsyncEnumerable<T>: unbounded/bounded with backpressure, single/multi consumer; under the hood uses linked lists and IValueTaskSource to recycle awaiter state.
  • IL inspection: ildasm, ILSpy, dnSpy, dotPeek. SharpLab shows IL + JIT asm in browser.
  • Roslyn scripting (Microsoft.CodeAnalysis.CSharp.Scripting): evaluate C# strings; powers REPLs and embeddable script engines.
  • Dynamic via DLR: dynamic keyword + System.Linq.Expressions + DynamicObject/ExpandoObject — interop with Python/Ruby/JS-style late binding.
  • UnsafeAccessor (.NET 8+): zero-overhead access to private members without reflection.
  • Custom interceptors (preview): a source generator can replace specific call sites at compile time.

7. Idioms & style

  • Naming: PascalCase for types, methods, properties, events, namespaces, constants; camelCase for parameters and local variables; _camelCase for private fields; IPascalCase for interfaces; TPascalCase for type parameters.
  • Formatter: dotnet format (built into SDK); EditorConfig (.editorconfig) is canonical for style + analyzer rules. Roslyn analyzers ship with the SDK.
  • Idiomatic patterns: prefer var when the type is obvious; use using for IDisposable; expression-bodied members for one-liners; records for value-equality types; init setters; positional records for DTOs; pattern matching over downcasts; nameof() everywhere; required properties (C# 11); primary constructors (C# 12); IReadOnlyList<T> in public APIs; nullable reference types enabled (<Nullable>enable</Nullable>).
  • Reviewers look for: missing ConfigureAwait(false) in libraries, sync-over-async (.Result/.Wait()), boxing in hot paths, IEnumerable enumerated multiple times, missing IDisposable.Dispose paths, suppression of nullable warnings without justification, exception swallowing, blocking on UI thread.

8. Ecosystem

  • Web: ASP.NET Core (MVC, Razor Pages, Minimal APIs, Blazor Server / Blazor WebAssembly), SignalR (real-time), YARP (reverse proxy).
  • Cloud: .NET Aspire (orchestration), Azure SDK for .NET, Dapr.
  • Data: Entity Framework Core, Dapper, Npgsql, MongoDB.Driver.
  • Mobile/Desktop: .NET MAUI, Avalonia, Uno Platform, WPF, WinForms, WinUI 3.
  • Games: Unity (C# scripting), Stride, Godot Mono, MonoGame.
  • ML: ML.NET, TorchSharp, ONNX Runtime, Microsoft.SemanticKernel.
  • Testing: xUnit (most common), NUnit, MSTest; Moq/NSubstitute/FakeItEasy; FluentAssertions; Bogus (test data); Verify (snapshot); Testcontainers.
  • Doc tools: DocFX, XML doc comments (///), Sandcastle.
  • Notable users: Microsoft (Bing, Office, Azure), Stack Overflow, Unity (engine + games), GitHub (parts), JetBrains (Rider/ReSharper internals), Bloomberg.

9. Gotchas

  • async void swallows exceptions and breaks composition — only legal for event handlers.
  • Sync-over-async deadlocks in legacy SyncContext (ASP.NET Framework, WPF). .Result/.Wait() is forbidden.
  • IDisposable not in using equals leak. Resharper/analyzer catches it.
  • LINQ deferred execution: var q = list.Where(...) doesn’t run until enumerated; multiple enumerations re-execute the query (and re-hit the database).
  • Captured loop variable (pre-C# 5 in for, still pre-C# 9 in some foreach scenarios) — modern C# captures per-iteration.
  • struct mutation through interface = silent boxing.
  • Default value of reference types is null; nullable reference types help but only as warnings.
  • == on string is value equality; on object it’s reference. On records: value-based.
  • DateTime.UtcNow vs DateTime.Now vs TimeProvider; prefer DateTimeOffset and TimeProvider.
  • ConfigureAwait(false) discipline: mandatory in libraries, optional in app code with no SyncContext (ASP.NET Core has none).
  • NativeAOT incompatibilities: dynamic codegen, Assembly.LoadFrom, untyped reflection over generics — all break trimming.
  • Span<T> cannot be field of class, cannot escape async/iterators, cannot be in arrays.
  • Equals/GetHashCode symmetry: must override both; mutating a key in a Dictionary<K,V> corrupts it.

10. Citations