A comprehensive deep-dive into C# 13 & C# 14 — the latest versions — covering every new feature, code examples, performance guidance, and tooling.
SECTION 01
Introduction to C#
C# (pronounced "C Sharp") is a modern, object-oriented, type-safe programming language developed by Microsoft as part of the .NET platform. First introduced in 2000 by Anders Hejlsberg and his team, C# has grown into one of the most widely used programming languages in the world, powering enterprise web applications, cloud services, desktop software, mobile apps, and game development with Unity.
The language is designed to be simple, modern, general-purpose, and object-oriented. Its design philosophy emphasizes developer productivity, code safety, and performance — a balance that has kept it relevant through two decades of rapid technological change.
Key Characteristics
Strongly typed with static type checking at compile time
Object-oriented: encapsulation, inheritance, and polymorphism
Component-oriented with properties, events, and attributes
Cross-platform via .NET: Windows, Linux, and macOS
Continuously evolving with annual releases tied to the .NET SDK
Version History
| Version | Year | .NET Platform | Milestone Features |
|---|
C# 1.0 | 2002 | .NET 1.0 | Classes, interfaces, delegates, events |
C# 2.0 | 2005 | .NET 2.0 | Generics, iterators, nullable types, anonymous methods |
C# 3.0 | 2007 | .NET 3.5 | LINQ, lambda expressions, extension methods |
C# 4.0 | 2010 | .NET 4.0 | Dynamic binding, named/optional parameters |
C# 5.0 | 2012 | .NET 4.5 | async/await, caller info attributes |
C# 6.0 | 2015 | .NET 4.6 | Null-conditional operator, string interpolation |
C# 7.x | 2017–18 | .NET 4.7 / Core 2.x | Pattern matching, tuples, local functions |
C# 8.0 | 2019 | .NET Core 3.0 | Nullable reference types, async streams |
C# 9.0 | 2020 | .NET 5 | Records, init-only setters, top-level programs |
C# 10.0 | 2021 | .NET 6 | Global usings, file-scoped namespaces |
C# 11.0 | 2022 | .NET 7 | Raw string literals, required members |
C# 12.0 | 2023 | .NET 8 | Primary constructors, collection expressions |
C# 13.0 | Nov 2024 | .NET 9 | params collections, new lock type, ref struct interfaces |
C# 14.0 | Nov 2025 | .NET 10 | Extension members, field keyword, null-conditional assignment |
SECTION 02
What's New in C# 13
C# 13 was released in November 2024 alongside the .NET 9 SDK. The theme of this release is focused on precision improvements — enhancing performance, expanding flexibility for low-level programming with ref structs, and streamlining everyday development patterns.
2.1 — params Collections
One of the most developer-friendly changes in C# 13 is the expansion of the params modifier. Previously restricted exclusively to single-dimensional arrays, params now works with any recognized collection type, including Span<T>, ReadOnlySpan<T>, IEnumerable<T>, ICollection<T>, IList<T>, and their read-only counterparts.
When an interface type is used, the compiler synthesizes the storage for the arguments supplied. This change improves performance by avoiding array allocations when using span-based overloads.
C#
// Before
(C# 12 and earlier)void Log(params string[] messages) { }
// After
(C# 13) — params with any collection typevoid Log(params List<string> messages) { }
void LogSpan(params ReadOnlySpan<string> messages) { }
// Spans as params — zero heap allocation
public void Concat<T>(params ReadOnlySpan<T> items)
{
for (int i = 0; i < items.Length; i++)
Console.Write(items[i]);
}
2.2 — New lock Type and Semantics
The .NET 9 runtime introduces System.Threading.Lock — a dedicated type for thread synchronization that provides better semantics than the old System.Threading.Monitor approach. The C# compiler automatically detects when a lock statement targets a Lock object and emits optimized code using Lock.EnterScope().
The best part: this is fully backward compatible. Simply change the type of your lock field from object to Lock and the compiler does the rest. No other code changes required.
C#
// Before (C# 12): plain objectprivate readonly object _lock = new object();
// After (C# 13): dedicated Lock typeprivate readonly Lock _lock = new Lock();
public void SafeIncrement()
{
lock (_lock)
{
// Compiler generates Lock.EnterScope() — faster for uncontended locks
counter++;
}
}
2.3 — New Escape Sequence: \e
C# 13 introduces \e as a character literal escape sequence for the ESCAPE character (Unicode U+001B). Previously developers used \u001b or \x1b, the latter being error-prone because subsequent valid hex digits were absorbed into the sequence. The new \e is unambiguous.
C#
// Old way (ambiguous with hex digits that follow)string red = "\u001b[31mRed Text\u001b[0m";
// New way (C# 13) — clean and unambiguousstring red = "\e[31mRed Text\e[0m";
Console.WriteLine(red);
2.4 — Implicit Index Access in Object Initializers
The "from-the-end" index operator (^) can now be used inside object initializer expressions for single-dimension collections. Prior to C# 13, the ^ operator was not permitted in initializer contexts.
C#
public class TimerRemaining
{
public int[] buffer { get; set; } = new int[10];
}
// C# 13: ^ operator now allowed in object initializervar countdown = new TimerRemaining()
{
buffer =
{
[^1] = 0,
[^2] = 1,
[^3] = 2,
// ... counts down from 9 to 0
[^10] = 9
}
};
2.5 — ref and unsafe in Iterators and Async Methods
Before C# 13, iterator methods (using yield return) and async methods could not declare local ref variables or use unsafe contexts. C# 13 relaxes these restrictions in a verifiably safe way:
Async methods can declarereflocal variables andref structlocal variables
These variables cannot be accessed across anawaitoryield returnboundary
The compiler enforces these rules at compile time
Types likeReadOnlySpan<T>can be used more freely in these contexts
2.6 — ref struct Interfaces
Before C# 13, ref struct types (such as Span<T>) were not allowed to implement interfaces. C# 13 removes this limitation. ref struct types can now declare interface implementations, though a ref struct still cannot be converted to an interface type (which would require boxing, violating ref safety). Interface methods are accessible through generic type parameters using the allows ref struct anti-constraint.
2.7 — allows ref struct Anti-Constraint
Generic type and method declarations can now include allows ref struct as an anti-constraint, enabling Span<T> and other ref structs to be used with generic algorithms.
C#
// T can be a ref struct (e.g. Span<int>)public class C<T> where T : allows ref struct
{
public void M(scoped T p)
{
// ref safety rules enforced on all uses of T
}
}
2.8 — Partial Properties and Indexers
C# 13 extends partial type support to include properties and indexers — particularly valuable for source generators, where one file contains the declaration and another provides the implementation.
C#
// Generated file — declaration onlypublic partial class MyClass
{
public partial int Count { get; set; }
}
// Developer file — implementationpublic partial class MyClass
{
private int _count;
public partial int Count
{
get => _count;
set => _count = value;
}
}
2.9 — Overload Resolution Priority
Library authors can use the [OverloadResolutionPriority] attribute to designate one overload as preferred when multiple are equally applicable. Higher priority wins. This is useful for introducing new, more efficient overloads without breaking existing callers.
C#
[OverloadResolutionPriority(1)] // preferred overloadpublic void Process(ReadOnlySpan<char> data) { /* efficient */ }
// Fallback (lower priority)public void Process(string data) { }
2.10 — Method Group Natural Type Improvements: The compiler now prunes non-applicable candidate methods at each scope progressively, rather than building a full set of candidates across all scopes. This more closely aligns with general overload resolution rules and can resolve previously ambiguous method group type inference.
SECTION 03
What's New in C# 14
C# 14 was released in November 2025 with .NET 10. This release delivers several long-awaited features — some originally planned for C# 13 — as well as new innovations that further streamline everyday C# code.
3.1 — Extension Members
Extension members are a major evolution of C#'s existing extension methods. Where extension methods allowed developers to add instance methods to existing types without modifying them, extension members go further — allowing extension properties, static methods, and other member types. This fills a long-standing gap in the language and opens new possibilities for expressive, fluent APIs.
C# 14
// Extension property on stringextension(string s)
{
public bool IsEmailAddress => s.Contains('@') && s.Contains('.');
public string Slugify() => s.ToLower().Replace(' ', '-');
}
// Usage — just like an instance memberstring email = "[email protected]";
bool valid = email.IsEmailAddress; // truestring slug = "Hello World".Slugify(); // "hello-world"
3.2 — field-Backed Properties
The field keyword (previewed in C# 13) is now fully supported. It provides direct access to the automatically generated backing field of a property, eliminating the need to manually declare a separate field when custom getter/setter logic is needed.
C# 14
// Before C# 14 — explicit backing field requiredprivate string _name;
public string Name
{
get => _name;
set => _name = value?.Trim() ?? string.Empty;
}
// C# 14 — use field keyword directlypublic string Name
{
get;
set => field = value?.Trim() ?? string.Empty;
}
3.3 — Null-Conditional Assignment
C# 14 extends the null-conditional operator (?.) to support assignments — assigning a value to a property or field only if the target is not null. This eliminates a very common null-check-before-assign pattern.
C# 14
// Before C# 14 — verbose null checkif (person != null) person.Name = "Alice";
// C# 14 — null-conditional assignment
person?.Name = "Alice";
// Works with nested chains too
order?.Customer?.Address?.City = "Cape Town";
3.4 — nameof with Unbound Generic Types
The nameof operator now supports unbound generic types. Previously, type arguments had to be specified to use nameof with a generic type.
C# 14
// Before C# 14 — had to specify type argumentstring name = nameof(List<int>); // "List"
// C# 14 — unbound genericstring name = nameof(List<>); // "List"string dict = nameof(Dictionary<,>); // "Dictionary"
3.5 — More Implicit Span Conversions
C# 14 expands the implicit conversion rules for Span<T> and ReadOnlySpan<T>, enabling more scenarios where these efficient, stack-allocated slice types can be used without explicit casts. This makes high-performance code more natural to write and reduces friction for developers adopting span-based APIs.
3.6 — Modifiers on Simple Lambda Parameters
Lambda expressions in C# 14 allow modifiers such as ref, out, and in on simple (implicitly typed) lambda parameters. Previously these modifiers required explicit parameter types.
C# 14
// ref modifier on implicitly typed lambda parameterIncrementDelegate increment = (ref x) => x++;
// out modifier — no need to write explicit typeTryParseDelegate tryParse = (out result) => { result = 42; return true; };
3.7 — Partial Events and Constructors
C# 14 further extends partial member support (which began in C# 13 with partial properties) to include partial events and partial constructors. This is valuable in code-generation scenarios where tools emit declarations and developers supply the implementations.
3.8 — User-Defined Compound Assignment Operators
C# 14 allows developers to explicitly overload compound assignment operators (+=, -=, *=, etc.), giving library authors fine-grained control over assignment semantics — including in-place mutation without creating copies.
C# 14
public static Vector operator +=(Vector left, Vector right)
{
left.X += right.X;
left.Y += right.Y;
return left; // in-place mutation, no copy
}
// UsageVector pos = new(0, 0);
pos += new Vector(5, 3); // calls custom += operator
SECTION 04
Best Practices & Guidance
Adopting C# 13 / 14 Features
Target the right SDK: C# 13 requires .NET 9 SDK; C# 14 requires .NET 10. Update your<TargetFramework>accordingly.
Use params collections for spans: Switch from array-based params toReadOnlySpan<T>orIEnumerable<T>for performance gains in hot paths.
Migrate lock targets: Replaceprivate readonly object _lockwithprivate readonly Lock _lockto get optimized synchronization at zero call-site cost.
Use field gradually: Introduce thefieldkeyword in new properties; no urgent need to refactor working code.
Prefer extension members over wrappers: When augmenting third-party types, use C# 14 extension members rather than inheritance or wrapper types.
Performance Feature Summary
| Feature | Version | Performance Impact |
|---|
params ReadOnlySpan<T> | C# 13 | Avoids heap allocation vs. array-based params |
New Lock type | C# 13 | Reduced overhead vs. Monitor for uncontended locks |
ref struct interfaces | C# 13 | Generic algorithms on stack-allocated types |
allows ref struct | C# 13 | Stack allocation in more generic contexts |
| Implicit Span conversions | C# 14 | Reduces unnecessary allocation at call sites |
| User-defined compound operators | C# 14 | In-place mutation without copies |
SECTION 05
Tooling & Ecosystem
SDK and IDE Requirements
| C# Version | SDK Required | Minimum VS 2022 | VS Code |
|---|
C# 13 | .NET 9 SDK | Version 17.12 | C# Dev Kit 1.x |
C# 14 | .NET 10 SDK | Version 17.14 | C# Dev Kit 2.x |
Language Version Configuration
C# automatically uses the latest language version when targeting the latest .NET SDK. You can pin or preview versions explicitly:
XML (.csproj)
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>14</LangVersion> <!-- or: 13, latest, preview -->
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Roslyn Analyzers
Microsoft provides official Roslyn analyzers included with the .NET SDK that can surface opportunities to apply new C# features in existing code. These analyzers are configurable via .editorconfig files and integrate with Visual Studio, VS Code, and CLI builds.
Conclusion
C# continues to evolve in a thoughtful, developer-centric way. C# 13 (November 2024) delivered meaningful improvements around performance — params collections, the new Lock type — low-level programming — ref struct interfaces, allows ref struct — and productivity with partial properties and implicit indexers. C# 14 (November 2025) continued this trajectory with long-anticipated features like extension members, field-backed properties, and null-conditional assignment.
Together, these releases reflect Microsoft's commitment to making C# simultaneously more expressive for high-level application development and more capable for high-performance, low-allocation scenarios. Whether you are building web APIs with ASP.NET Core, data pipelines, desktop apps, or game logic in Unity, these additions reduce ceremony and boost productivity.
Developers are encouraged to adopt C# 13 features by targeting .NET 9 today, and to begin exploring C# 14 by targeting .NET 10. The ecosystem of tooling, documentation, and community support around both releases is mature and ready.