Mungomash LLC
C# Versions

2002 – 2025

C# Versions

Every public release of the C# language — C# 1.0 in February 2002 through C# 14 in November 2025 — mapped to the .NET version that ships it, with the headline language features each one introduced. For the .NET runtime, BCL, and the corporate history (Hejlsberg, Roslyn, Connect(); 2014), see the sibling .NET Versions page.

Era

Pre-Roslyn — C# 1.0 – 5.0, 2002–2012, closed C++ compiler shipped inside Visual Studio
Roslyn — C# 6.0 – 8.0, 2015–2019, the rewritten-in-C# compiler-as-a-service
Annual — C# 9+, 2020 onward, locked to the November .NET cadence

C# × .NET mapping

Every C# release ships as part of a .NET / Visual Studio release. The compiler picks a default language version per target framework, and a project can opt in to a newer language version via <LangVersion> in the .csproj — but only up to the version the installed SDK supports. The table below is the high-traffic "what version of C# is in .NET 8?" lookup.

C# .NET / Framework Visual Studio Released
C# 14.NET 10VS 2026 (17.13)Nov 2025
C# 13.NET 9VS 2022 (17.12)Nov 2024
C# 12.NET 8VS 2022 (17.8)Nov 2023
C# 11.NET 7VS 2022 (17.4)Nov 2022
C# 10.NET 6VS 2022 (17.0)Nov 2021
C# 9.NET 5VS 2019 (16.8)Nov 2020
C# 8.0.NET Core 3.0VS 2019 (16.3)Sep 2019
C# 7.3.NET Core 2.1 / Framework 4.7.2VS 2017 (15.7)May 2018
C# 7.2.NET Core 2.0 / Framework 4.7.1VS 2017 (15.5)Dec 2017
C# 7.1.NET Core 2.0 / Framework 4.7VS 2017 (15.3)Aug 2017
C# 7.0.NET Framework 4.6.2 / .NET Core 1.0VS 2017 (15.0)Mar 2017
C# 6.0.NET Framework 4.6VS 2015Jul 2015
C# 5.0.NET Framework 4.5VS 2012Aug 2012
C# 4.0.NET Framework 4.0VS 2010Apr 2010
C# 3.0.NET Framework 3.5VS 2008Nov 2007
C# 2.0.NET Framework 2.0VS 2005Nov 2005
C# 1.2.NET Framework 1.1VS .NET 2003Apr 2003
C# 1.0.NET Framework 1.0VS .NET 2002Feb 2002

Default language version is determined by the target framework moniker (TFM) — e.g. net8.0 defaults to C# 12, net6.0 to C# 10. Override with <LangVersion> in the .csproj; see the "Find your version" block below.

Per-version language features

Version
C# 14
Annual
.NET 10
Nov 11, 2025
Field-backed properties; null-conditional assignment; extension members; broader collection-expression conversions.
  • Ships with .NET 10 and Visual Studio 2026 (17.13).
  • Field-backed properties — the field contextual keyword, allowing trivial property bodies to read and write the compiler-synthesized backing field without writing it out.
  • Null-conditional assignmentx?.Y = value assigns only if x is non-null, mirroring the long-existing null-conditional read.
  • Extension members — properties, indexers, and events as extension members, generalizing the C# 3 extension-method story.
  • Broader collection-expression conversions — more target types accept [a, b, c] implicitly.
  • Continued primary-constructor refinement and partial-property work from C# 12 / 13.
  • Implicit span conversions where source is an array of value type and target is ReadOnlySpan<T>.
Version
C# 13
Annual
.NET 9
Nov 12, 2024
params for any collection type; partial properties / indexers; lock-on-typed-statement; \e escape.
  • Ships with .NET 9 and Visual Studio 2022 (17.12).
  • params on any collection type — not just arrays. params Span<T>, params IEnumerable<T>, params ImmutableArray<T> all work.
  • Partial properties and indexers — the partial-method story extended to property and indexer declarations, primarily so source generators can split definition and body.
  • Lock-on-typed-statementSystem.Threading.Lock is a recognized lock target with compiler-validated scope.
  • \e escape for the ESC character.
  • Method group natural type improvements (better overload resolution).
  • ref / unsafe in iterators and async methods.
Version
C# 12
Annual
.NET 8
Nov 14, 2023
Primary constructors on classes; collection expressions; default lambda parameters; alias any type.
  • Ships with .NET 8 LTS and Visual Studio 2022 (17.8).
  • Primary constructors on classes and structs — the C# 9 primary-constructor syntax for records was generalized to all class and struct declarations. class Distance(double meters) brings the parameters in scope across the class body.
  • Collection expressionsint[] x = [1, 2, 3], List<int> y = [..xs, 4], Span<int> z = [a, b, c]. The .. spread operator extracts elements from another collection.
  • Default lambda parameters(int x = 5) => x, finally bringing lambdas to parity with method declarations.
  • Alias any typeusing Point = (int x, int y); works on tuples, pointers, arrays — not just named types.
  • ref readonly parameters — explicit syntax for the C# 7.2 read-only ref parameter pattern.
  • Inline arrays — [InlineArray(N)] for fixed-size struct buffers.
  • Experimental attribute — [Experimental] emits a build warning consumers must opt out of.
Version
C# 11
Annual
.NET 7
Nov 8, 2022
Raw string literals; list patterns; required members; generic attributes; UTF-8 string literals; generic math.
  • Ships with .NET 7 and Visual Studio 2022 (17.4).
  • Raw string literals"""-delimited multi-line literals that don't need escapes; great for embedded JSON and SQL.
  • List patternsarr is [1, 2, 3], arr is [_, var middle, _], arr is [.., 0]. Pattern matching across whole sequences.
  • Required membersrequired modifier on properties and fields means the constructor caller must initialize them via object initializer.
  • Generic attributes[MyAttribute<T>]; the long-requested feature (it had been technically reserved since C# 2 but never implemented).
  • UTF-8 string literals"hello"u8 compiles to a ReadOnlySpan<byte> of the UTF-8 bytes.
  • Generic mathINumber<T>, IFloatingPoint<T> static abstract members on interfaces; write polymorphic numeric code.
  • File-local types — file class for source-generator-only types invisible across files.
  • Newlines in string interpolation expressions; struct auto-default; pattern match Span<char> against constant strings.
Version
C# 10
Annual
.NET 6
Nov 8, 2021
Global usings; file-scoped namespaces; record structs; const string interpolation.
  • Ships with .NET 6 LTS and Visual Studio 2022 (17.0).
  • Global usingsglobal using System.Text; applies the using across every file in the project. Combined with the SDK-emitted implicit usings, ASP.NET Core Program.cs went from 30 lines of ceremony to 5.
  • File-scoped namespacesnamespace Foo; at file top, instead of an indented block. Saves a level of indentation across every file.
  • Record structs — the C# 9 record syntax extended to value types; immutable structs with structural equality and a with expression.
  • const string interpolation — const string s = $"v{N}"; when all interpolated values are also const.
  • Lambda improvements — explicit return types, attributes, natural delegate types.
  • Parameterless struct constructors and field initializers.
  • Extended property patterns — obj is { Prop.Sub: 5 }.
  • CallerArgumentExpression attribute — assertion libraries can show the actual expression text in failure messages.
Version
C# 9
Annual
.NET 5
Nov 10, 2020
First release of the annual cadence. Records, init-only setters, top-level statements, target-typed new.
  • First release of the new annual November cadence; ships with .NET 5 and Visual Studio 2019 (16.8).
  • Record typesrecord Person(string First, string Last);. Reference-typed, immutable by default, with structural equality, ToString, and a with expression for non-destructive mutation. The headline syntax addition since lambdas.
  • Init-only setters{ get; init; } properties; assignable in object initializers and constructors only, then read-only. Underpins records.
  • Top-level statements — a single Program.cs can be a sequence of top-level statements without a wrapping class Program { static void Main() {...} }.
  • Target-typed newList<int> x = new(); infers the constructor target from the declared type.
  • Pattern-matching enhancements — relational patterns (x is > 0), logical patterns (and, or, not), parenthesized patterns, type patterns without identifier.
  • Native-sized integers (nint, nuint); function pointers (delegate*); module initializers.
  • Covariant returns — an override can return a more derived type than the base method.
  • Source generators (Roslyn-side feature, but ergonomically a C# 9 release).

The annual cadence — November 2020. Above this line: the Annual era — one C# version per year, locked to the November .NET ship date. Below: the Roslyn era of feature-driven point releases (8.0 in Sep 2019, 7.x patches across 2017–2018). The cadence shift was a side-effect of the .NET annual cadence: when the runtime started shipping every November, the language started doing the same.

Version
C# 8.0
Roslyn
.NET Core 3.0
Sep 23, 2019
Nullable reference types; async streams; default interface methods; switch expressions; indices and ranges.
  • Ships with .NET Core 3.0 and Visual Studio 2019 (16.3). Not available on .NET Framework — the first language version that broke that bridge.
  • Nullable reference types — opt-in static null analysis. string means non-null; string? means nullable. Twenty years of NullReferenceException finally gets a static-checking story.
  • Async streamsIAsyncEnumerable<T>, await foreach, yield return from async iterators.
  • Default interface methods — interface members can have a default implementation. The trick that lets BCL interfaces grow new members without breaking implementers.
  • Switch expressionsx switch { 1 => "one", 2 => "two", _ => "?" }. Expression form of switch; pattern-matching exhaustiveness checking.
  • Indices and rangesarr[^1] for last element, arr[1..3] for slices. Index and Range as language-recognized types.
  • using declarations — using var x = new Foo(); auto-disposes at scope end without an indented block.
  • Static local functions; readonly struct members; null-coalescing assignment (x ??= y).
Version
C# 7.3
Roslyn
.NET Core 2.1
May 7, 2018
Generic constraints for enum / delegate / unmanaged; tuple equality; expression variables in initializers.
  • Ships with .NET Core 2.1 / .NET Framework 4.7.2; Visual Studio 2017 (15.7).
  • Generic constraints — where T : Enum, where T : Delegate, where T : unmanaged.
  • Tuple equality — (a, b) == (c, d).
  • Expression variables in initializers, query clauses, and out in field initializers.
  • Stackalloc array initializers; fixed on any blittable type.
  • System.ValueTuple patches; System.HashCode.
  • Indexing of fixed buffers without pinning.
Version
C# 7.2
Roslyn
.NET Core 2.0
Dec 4, 2017
in parameters; ref readonly; ref struct; private protected; Span<T>-related work.
  • Ships with .NET Core 2.0 / .NET Framework 4.7.1; Visual Studio 2017 (15.5).
  • in parameters — pass a value type by readonly reference; the missing piece for cheap large-struct argument passing.
  • ref readonly returns and locals; readonly struct.
  • ref struct — the type-system constraint that powers Span<T> safety. Stack-only, can't be boxed, can't be a generic type argument.
  • private protected — access modifier meaning "protected, but only from this assembly".
  • Conditional ref expressions; non-trailing named arguments; leading underscores in numeric literals (1_000_000).
Version
C# 7.1
Roslyn
.NET Core 2.0
Aug 14, 2017
async Main; default literal expressions; inferred tuple element names.
  • Ships with .NET Core 2.0 / .NET Framework 4.7; Visual Studio 2017 (15.3).
  • async Mainstatic async Task Main() works as an entry point. Ten years after async/await; finally allowed in Program.cs.
  • default literal expressions — int x = default; when the type can be inferred.
  • Inferred tuple element names — (x, y) from x and y variables produces a tuple with element names x and y.
  • Pattern matching with generics.
Version
C# 7.0
Roslyn
Framework 4.6.2
Mar 7, 2017
Tuples and deconstruction; pattern matching (initial); local functions; out variables; ref returns.
  • Ships with .NET Framework 4.6.2 and .NET Core 1.0; Visual Studio 2017 (15.0). The first release on the new ".NET Standard"-led versioning posture.
  • Tuples and deconstruction(int, string) Method() { return (1, "a"); }; var (n, s) = Method();. System.ValueTuple as the underlying type.
  • Pattern matching (initial)obj is int n, switch (obj) { case int n when n > 0: ... }. The seed of the multi-version pattern-matching expansion.
  • Local functions — methods nested inside other methods; closures over enclosing locals.
  • out variablesint.TryParse(s, out var n); declare the variable inline.
  • ref returns and locals — pass references through return values; the foundation for the C# 7.2 / 8 performance work.
  • Discards (_); throw expressions; expression-bodied accessors / constructors / finalizers; generalized async return types (ValueTask<T>).
  • Binary literals (0b_1010_0010); digit separators in numeric literals.
Version
C# 6.0
Roslyn
Framework 4.6
Jul 20, 2015
First Roslyn release. String interpolation; null-conditional ?.; nameof; expression-bodied members; auto-property initializers.
  • Ships with .NET Framework 4.6 and Visual Studio 2015. The first release of the Roslyn compiler — the C# / VB compilers had been rewritten in C# itself and open-sourced under Apache 2.0 in April 2014. See the .NET page's Roslyn rewrite section.
  • String interpolation$"Hello, {name}!". The flagship syntactic addition; ended a decade of String.Format.
  • Null-conditional operatorobj?.Prop?.Sub, arr?[0]. Short-circuits to null on any null link.
  • nameofnameof(MyProperty) compiles to "MyProperty"; refactor-safe parameter-name and member-name strings.
  • Expression-bodied members — public int X => _x;.
  • Auto-property initializers — public int X { get; } = 5;; getter-only auto-properties.
  • Exception filters — catch (Exception ex) when (ex.Code == 42); await in catch and finally blocks.
  • Static usingusing static System.Math;; dictionary initializers.
  • The release Microsoft used to demonstrate the new open-source Roslyn-based future; almost every C# 6 feature could be implemented as a Roslyn compiler analyzer / refactoring.

The Roslyn rewrite — April 2014 / July 2015. Above this line: the Roslyn era — the C# / VB compilers were rewritten in C# itself, open-sourced in April 2014, and shipped GA with C# 6 in July 2015. Below: the original closed-source Pre-Roslyn compiler line that ran from C# 1.0 through C# 5.0. The compiler-as-a-service architecture made source generators, real-time analyzers, and the modern Visual Studio / VS Code experience possible. See the .NET page's Roslyn rewrite section.

Version
C# 5.0
Pre-Roslyn
Framework 4.5
Aug 15, 2012
async / await; caller info attributes.
  • Ships with .NET Framework 4.5 and Visual Studio 2012.
  • async / await — the entire release. The state-machine rewrite that turned synchronous-looking code into asynchronous task chains, with Task / Task<T> as the awaited types. C# 5 is sometimes described as "the async release" because that was effectively the only feature.
  • Caller info attributes — [CallerMemberName], [CallerFilePath], [CallerLineNumber] for diagnostic helpers and INotifyPropertyChanged-style code without strings.
  • The release that turned C# back into a serious competitor to Java for application development — async / await predated equivalent constructs in Java by ten years.
Version
C# 4.0
Pre-Roslyn
Framework 4.0
Apr 12, 2010
dynamic; named / optional arguments; generic covariance and contravariance.
  • Ships with .NET Framework 4.0 and Visual Studio 2010.
  • dynamic typing — the dynamic keyword opted into late-bound member resolution via the DLR (Dynamic Language Runtime). Originally pitched for COM interop and IronPython / IronRuby integration.
  • Named and optional argumentsMethod(arg2: x, arg1: y) and void M(int x = 5). Office interop ergonomics, mostly.
  • Generic covariance and contravarianceIEnumerable<Cat> can be assigned to IEnumerable<Animal> via the out / in variance annotations on type parameters.
  • Embedded interop types — the "no PIA" deployment story for Office add-ins.
Version
C# 3.0
Pre-Roslyn
Framework 3.5
Nov 19, 2007
LINQ; lambda expressions; extension methods; anonymous types; var; expression trees.
  • Ships with .NET Framework 3.5 and Visual Studio 2008. The single largest leap in the C# language story until C# 8 / 9.
  • LINQ (Language-Integrated Query) — the headline. from x in xs where x > 0 select x compiles to xs.Where(x => x > 0) via lambda + extension method expansion. The supporting language features below all exist primarily to make LINQ work.
  • Lambda expressions(x, y) => x + y. Replaced anonymous methods (C# 2) for most uses.
  • Extension methods — static methods declared with a this first parameter, callable as if they were instance members of the receiver. Made IEnumerable<T>.Where(...) work.
  • Anonymous typesnew { Name = x.Name, Count = xs.Count() }.
  • var — local variable type inference; the syntactic enabler for anonymous types.
  • Expression treesExpression<Func<...>> for code-as-data; the trick that made LINQ-to-SQL and Entity Framework possible.
  • Object and collection initializers; automatic properties; partial methods.
  • Lead designed by Anders Hejlsberg and the C# team in collaboration with Erik Meijer (the LINQ design lead).
Version
C# 2.0
Pre-Roslyn
Framework 2.0
Nov 7, 2005
Generics; iterators (yield return); anonymous methods; partial classes; nullable types.
  • Ships with .NET Framework 2.0 (CLR 2.0) and Visual Studio 2005.
  • Generics — with reified type information at runtime, unlike Java's erasure-based generics. The CLR 2.0 release is what made List<T>, Dictionary<K, V>, and the rest of System.Collections.Generic possible. Don Syme's pre-Microsoft research at MSR Cambridge prefigured this design.
  • Iteratorsyield return / yield break. Lazy enumerable sequences with state-machine rewriting; the foundation under LINQ-to-Objects two years later.
  • Anonymous methodsdelegate(int x) { return x + 1; }. Replaced two years later by C# 3 lambdas.
  • Partial classes — split a class definition across multiple files; the trick that made WinForms designer-generated code clean.
  • Nullable value typesint? / Nullable<T>; HasValue, Value, ?? coalescing operator.
  • Property accessor accessibility modifiers ({ get; private set; }); static classes; covariance and contravariance for delegates.
  • The release that turned C# from a Java alternative into a notably more productive enterprise language.
Version
C# 1.2
Pre-Roslyn
Framework 1.1
Apr 24, 2003
Minor: foreach disposes IEnumerator when it implements IDisposable.
  • Ships with .NET Framework 1.1 and Visual Studio .NET 2003. Sometimes labeled "C# 1.1" or "C# 1.0 SP1" — Microsoft's own per-doc references vary.
  • The substantive change: foreach over an IEnumerator would call Dispose on the enumerator if it implemented IDisposable. A small fix with significant downstream implications for resource cleanup.
  • Otherwise a stability release; the language story is essentially identical to 1.0.
Version
C# 1.0
Pre-Roslyn
Framework 1.0
Feb 13, 2002
First release. Classes, structs, interfaces, delegates, events, properties, indexers, attributes; foreach; using; unsafe.
  • Ships with .NET Framework 1.0 and Visual Studio .NET 2002. The first release; designed by Anders Hejlsberg and the C# team starting in 1999 (Hejlsberg moved to Microsoft from Borland in 1996).
  • Object-oriented core — classes, structs, interfaces, abstract classes, virtual / override methods, single inheritance with multiple-interface implementation.
  • Delegates and events — first-class callable types; the model under every C# UI framework.
  • Properties and indexers — getter/setter pairs as first-class language constructs (vs. Java's getter/setter naming convention).
  • Attributes — declarative metadata, the seed of every later framework's annotation-driven configuration.
  • foreach loop; using statement for deterministic disposal; unsafe code with pointer arithmetic; verbatim string literals (@"..."); pre-processor directives (#if, #region); XML documentation comments.
  • No generics, no nullable types, no anonymous methods, no LINQ — all of those came later. Collections were untyped ArrayList / Hashtable.
  • The release that turned a research project into the language under the entire .NET ecosystem.

Click any row to expand. Each row has a stable id for sharing — e.g. /data/csharp/versions/#csharp-12, #csharp-8, #csharp-1. Per-version "what's new" pages live under learn.microsoft.com/dotnet/csharp/whats-new; design discussions and JEP-style proposals are at github.com/dotnet/csharplang.

The C# language design tradition

Anders Hejlsberg led the C# language design from before the language had a name through C# 7 (when he moved full-time to TypeScript at Microsoft). The corporate context — Hejlsberg's earlier work on Turbo Pascal and Delphi at Borland, his 1996 move to Microsoft, the broader .NET launch in 2002, the relationship to Sun v. Microsoft and the J/Direct era — lives on the .NET Versions page. The language design tradition is what's worth covering here.

Three patterns recur across twenty-three years of releases. Major features arrive in adjacent versions, supporting a single thesis. C# 3 introduced lambdas, extension methods, anonymous types, expression trees, and var — not as five independent additions but as the syntactic surface for LINQ. C# 7 introduced tuples, deconstruction, pattern matching, and out variables — not five things, but the surface for the multi-version pattern-matching expansion that landed across 7, 8, 9, 10, and 11. C# 9 introduced records, init-only setters, top-level statements, and target-typed new — the surface for the immutability-and-data-classes thesis.

The language reaches into the runtime when it needs to. Generics in C# 2 required CLR 2.0; async / await in C# 5 required runtime cooperation for the state-machine rewrite to support Task; ref struct in 7.2 required runtime checks for stack-only types; static abstract interface members in 11 required runtime support for generic math. The C# team and the runtime team work in lockstep. And new features ship as previews, not surprises. Records had four years of preview discussion on dotnet/csharplang before C# 9 shipped them; primary constructors had eight years (the original C# 6 proposal was withdrawn, then revived for C# 9 records, then generalized in C# 12). Reading a C# release note is rarely a shock; the design conversations are public for years before the syntax goes final.

Generics — reified, not erased (2005)

C# 2 / CLR 2.0 introduced generics with runtime-preserved type information: List<int> and List<string> are different types at runtime, with different JIT-emitted code per type parameter for value types. Java's generics, shipped one year earlier in Java 5, were implemented via type erasure — the type parameter is checked at compile time but stripped from the generated bytecode. The two approaches are the most cited language-design contrast in the C#-vs-Java conversation: erased generics are simpler to implement, preserve runtime compatibility with pre-generics code, and integrate trivially with reflection; reified generics enable specialized code per value-type instantiation, allow typeof(T) at runtime, and enable BCL designs like Span<T> that would be impossible under erasure. C# 11's static abstract interface members and the C# 13 generic-math story both depend directly on reification.

LINQ — the 2007 turn

LINQ (Language-Integrated Query), introduced with C# 3 / .NET Framework 3.5 in November 2007, is the largest leap in the C# language story until pattern matching and records in C# 8 / 9. The query syntax (from x in xs where p(x) select f(x)) is sugar over a pipeline of extension-method calls (xs.Where(p).Select(f)); the underlying types are IEnumerable<T> for in-memory queries and IQueryable<T> for code-as-data queries that providers translate to SQL or remote APIs.

The supporting features all exist primarily because LINQ requires them: lambda expressions (the predicate / projection syntax), extension methods (so Where and Select can be defined externally to IEnumerable), anonymous types (so select new { x.Name, x.Count } works), var (so anonymous types can be assigned), and expression trees (so IQueryable's lambdas can be inspected and translated to SQL by EF and LINQ-to-SQL). Erik Meijer led the LINQ design with Anders Hejlsberg, building on his Haskell-influenced work at Microsoft Research; the extension-method shape of the API directly reflects monadic comprehensions in functional languages.

async / await — the 2012 release

async / await shipped in C# 5 / .NET Framework 4.5 in August 2012. Effectively the entire release — C# 5 had only one other notable feature (caller info attributes). The compiler rewrites a method body containing await into a state machine that resumes on completion of the awaited Task; the developer keeps writing what looks like sequential code while the runtime handles the asynchronous continuation. The pattern is now standard across mainstream languages (JavaScript, Python, Rust, Kotlin, Swift, eventually Java with virtual threads), but C# was first by ten-plus years on most of them. Mads Torgersen led the design with Stephen Toub on the Task Parallel Library / runtime side; the project had been in research at MSR as "Cw" (C-omega) since the early 2000s. The release that turned C# back into a serious productivity competitor against Java for application development.

Roslyn — the compiler-as-a-service rewrite (2014)

The original C# and VB compilers (csc.exe / vbc.exe) were written in C++, started in the late 1990s, and shipped roughly the same compiler frontend across C# 1.0 through 5.0. By the early 2010s the codebase couldn't keep up with what Visual Studio needed for IntelliSense, refactorings, real-time analyzers, and compile-on-keystroke feedback. Microsoft started rewriting the compilers in C# itself around 2010 — the Roslyn project, named after a Seattle suburb. Roslyn was open-sourced under the Apache 2.0 license in April 2014 and shipped GA with C# 6 and Visual Studio 2015 in July 2015. See the .NET page's Roslyn rewrite section.

The compiler-as-a-service architecture exposes the compiler's syntax trees, semantic model, and binding logic as a public API. The downstream consequences for C# the language are larger than they sound. Real-time analyzers (the squigglies in your IDE) became cheap to write; the BCL ships dozens. Source generators (C# 9, 2020) let library authors generate code at compile time, looking at the consumer's type tree — the foundation under System.Text.Json's zero-reflection mode, the LoggerMessage source generator, the regex source generator, and (eventually) most of the runtime's reflection-heavy paths. IDE refactorings can be bundled with libraries (an analyzer NuGet package can ship its own refactoring code-fix). Most C# 6+ syntax features are implemented as Roslyn passes, not as runtime changes — which is why C# 6+ runs on every .NET runtime that supports the IL Roslyn emits, including .NET Framework 4.5+.

Nullable reference types — the C# 8 opt-in (2019)

Nullable reference types, shipped in C# 8 in September 2019, gave reference types the same opt-in nullability story value types had had since C# 2: string means non-null, string? means nullable, and the compiler emits warnings (not errors, configurably) when nulls cross a non-null boundary. The "rollout problem" was the design's hardest part: every existing C# codebase ever written was full of references that could be null but weren't annotated. The team chose opt-in via <Nullable>enable</Nullable> in the .csproj — per-project, per-file, or per-block via #nullable enable. Existing code defaults to "oblivious" semantics; new code defaults to "enabled" in templates from .NET 6 forward. The .NET BCL itself was annotated across .NET 5 and 6 over multiple releases.

Pattern matching — the multi-release expansion (2017–2024)

Pattern matching arrived in C# 7 (March 2017) as obj is T name and switch (obj) { case T n when ...: } — a small initial surface. Across the next four years it grew into one of the language's defining features:

  • C# 7 — type patterns, constant patterns, when guards in switch statements.
  • C# 8 — switch expressions, property patterns (obj is { Name: "Joe" }), tuple patterns, positional patterns (with Deconstruct), recursive patterns.
  • C# 9 — relational patterns (x is > 0), logical patterns (and / or / not), parenthesized patterns, type patterns without an identifier.
  • C# 10 — extended property patterns (obj is { Sub.Prop: 5 }).
  • C# 11 — list patterns (arr is [1, _, 3]); span pattern matching against constants.
  • C# 13 — refinements to method group resolution that flow into pattern-matching positions.

The cumulative effect is that switch expressions are now usable as the natural syntax for type-driven branching across BCL types — x switch { int n when n > 0 => "positive int", string { Length: 0 } => "empty string", [] => "empty seq", null => "null", _ => "?" }. The exhaustiveness checker (combined with sealed hierarchies and required members) covers most of what discriminated unions in functional languages provide, without C# adopting them as a formal construct.

Records and the immutability turn (2020–2021)

Records (C# 9, November 2020) and record structs (C# 10, November 2021) gave C# concise immutable data carriers. record Person(string First, string Last); compiles to a class with init-only properties for First and Last, structural equality (two records compare equal iff their fields are equal), a ToString that prints the property values, a Deconstruct for pattern matching, and a with expression for non-destructive mutation (person with { First = "Alice" }). The supporting init-only setters ({ get; init; }) shipped in the same release; they're the constructor-or-object-initializer-only setter pattern that records depend on.

The immutability turn extends across multiple releases. C# 11 required members let constructors enforce object-initializer-set fields without writing the constructor body. C# 12 primary constructors generalized the record syntax to all classes and structs. The combined effect is that idiomatic modern C# now leans heavily on immutable data shapes — closer to F# than to Java in feel.

The performance language — Span<T> and ref struct (2017–)

Starting with C# 7.2 in late 2017, the language gained a parallel performance dialect centered on ref struct, readonly struct, in parameters, ref readonly, and the Span<T> / Memory<T> / ReadOnlySpan<T> types. The headline shape: Span<T> is a stack-only structure that views a contiguous chunk of memory (managed array, native pointer, stackalloc buffer) without allocating; ref struct is the type-system constraint that keeps it from escaping to the heap. The dialect is opt-in — idiomatic application code never has to touch it — but it underlies the modern .NET I/O, JSON, parsing, and networking stacks. The annual cadence has continued to add features (UTF-8 string literals in C# 11, inline arrays in C# 12, allows-ref-struct generic constraints in C# 13, implicit span conversions in C# 14) that incrementally close the gap with C and Rust on tight-loop performance, while keeping the safety story C# is known for.

The annual November cadence (2020–)

Every November since C# 9 / .NET 5 (November 2020), a new C# major version ships alongside a new .NET major version. This is a side-effect of the .NET annual cadence (covered on the .NET page) more than a deliberate language-cadence decision — but it is the cadence for both. The benefits and costs are similar: features ship when ready instead of waiting on a release-blocker; previews let the community try features at scale before they're set in stone; LangVersion lets a project pin to an older version if needed.

People who actually shaped C#

Original C# team: Anders Hejlsberg (lead language designer, Distinguished Engineer; Turbo Pascal and Delphi at Borland; moved to Microsoft 1996; led C# through C# 7), Scott Wiltamuth (early team lead), Eric Lippert (C# language design and compiler 2004–2012; widely-cited industry educator), Mads Torgersen (current C# language design lead; took over from Hejlsberg).

LINQ era: Erik Meijer (LINQ design; Microsoft Research; Haskell influence), Don Syme (F# designer; influenced C# 2 generics design from the runtime side), Cyrus Najmabadi (lambda and expression-tree work).

async / await era: Mads Torgersen (language design lead), Stephen Toub (Task Parallel Library, performance lead, the public face of the annual "Performance Improvements in .NET N" mega-posts), Lucian Wischik (state-machine rewrite).

Roslyn era: Neal Gafter (early Roslyn; pattern matching design; later moved to Java's pattern matching at Oracle), Aleksey Tsingauz, Jared Parsons (long-time Roslyn and C# compiler engineer).

Modern team: Mads Torgersen (language design lead, current), Jared Parsons (compiler), Bill Wagner (docs and community), Kathleen Dollard (PM), Andy Gocke (runtime/language interop). Public face: the .NET YouTube channel, the LDM (Language Design Meeting) notes, and devblogs.microsoft.com/dotnet/category/csharp.

Find your C# version — in the terminal

The browser cannot detect what version of C# is in use on your machine. Run one of these in your terminal to see what your SDK supports and what version your project is set to.

What's installed?

The C# compiler ships with the .NET SDK; dotnet is the front door for everything below.

$ dotnet --version             # active SDK; implies a maximum supported C# version
$ dotnet --list-sdks           # every SDK installed side-by-side
$ csc -langversion:?           # every C# version this compiler accepts as <LangVersion>
$ dotnet build /p:LangVersion=preview # compile with the preview LangVersion (in-flight features)

Pin a project to a specific C# version

Default LangVersion is determined by the TargetFrameworknet8.0 defaults to C# 12, net6.0 to C# 10, netstandard2.0 to C# 7.3. Override explicitly when you need to.

<!-- in your .csproj -->
<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  <LangVersion>12.0</LangVersion>
  <Nullable>enable</Nullable>
</PropertyGroup>

Valid LangVersion values: 1, 2, 3, 4, 5, 6, 7, 7.1, 7.2, 7.3, 8, 9, 10, 11, 12, 13, 14, latest, latestMajor, preview.

What C# version is this project compiling under?

When in doubt, ask the build itself.

$ dotnet build --verbosity:diag | grep "langversion"
$ dotnet build --getProperty:LangVersion
$ dotnet msbuild --getProperty:LangVersion

Print the C# version from inside source code

A #error version directive emits the active LangVersion in the compiler error message — the most precise way to check, with no shell tricks.

// Anywhere in a .cs file:
#error version
// CS8304: Compiler version: '4.12.0'. Language version: 12.0.

Sources: learn.microsoft.com/dotnet/csharp/whats-new; dotnet/csharplang; dotnet/roslyn; devblogs.microsoft.com/dotnet/category/csharp; and the books and LDM notes cited inline. For corporate history (Hejlsberg, the 2002 launch, the Roslyn open-sourcing, the Connect(); 2014 pivot), see the sibling .NET Versions page. Last updated April 2026.

Mungomash LLC · More data pages