C#  

What's new in C# 14

Overview

C# 14 is focused mainly on developer ergonomics: small but meaningful improvements that reduce boilerplate, let you express intent more clearly, improve performance in certain scenarios, and allow more flexibility. These aren’t massive paradigm shifts, but many “papercuts” get fixed.

Key New Features in C# 14

Here are the main new language features:

FeatureWhat it enables / Why it helps
nameof supports unbound generic typesYou can now use nameof(List<>) (an unbound generic) to get "List" instead of only allowing nameof(List<int>) or similar. Helps for reflection, logging, diagnostics, or any scenario where you want the generic type name without specifying type parameters.
Implicit conversions for Span<T> / ReadOnlySpan<T>C# 14 adds “first-class” support for Span<T> and ReadOnlySpan<T>, allowing more natural usage, conversions between T[], Span<T>, ReadOnlySpan<T>, better generic inference etc. This helps performance in code that works closely with memory, avoids unnecessary allocations or copying.
Simple lambda parameters with modifiersBefore in lambdas, if you wanted parameter modifiers like ref, out, in, scoped, etc., you had to also explicitly declare the parameter types. Now you can omit types and still use modifiers: e.g. (text, out result) => …. Means your code is less verbose but still expressive.
field-backed auto-properties (the field contextual keyword)With this, auto-properties can have bodies in get/set and refer to a compiler generated backing field using the contextual keyword field. So instead of having to manually declare a private field when you need logic in setter/getter, you can just write logic referring to field. Improves readability and reduces boilerplate.
Partial constructors & partial eventsPartial members—previously you had partial methods, properties, indexers—are now extended to constructors and events. This helps in source generation, code generation, splitting definitions vs implementation, etc.
Extension membersYou can now declare extension properties (not just extension methods) and extension members that extend the type rather than an instance. This gives more flexibility in extending types in a “static” way or adding properties etc.
Null-conditional assignmentThis is “left-side null conditional” assignment: being able to use ?. on the left side in assignment contexts. E.g., possibly something like obj?.Property = value; where obj might be null. Reduces boilerplate checking for null.
User-defined compound assignment operatorsPreviously, compound assignment operators like +=, *= etc. for user types were limited: some would simply translate into their underlying binary ops or full expressions, but you couldn't customize them. In C# 14 you can define user-defined compound assignment operators that modify in place, which can help performance in value types or when avoiding unnecessary copies.

Breaking Changes / Things to Be Aware Of

Along with the new features, there are some changes that could break existing code or require adjustment. Some are small “gotchas” when you adopt C# 14 as the language version.

Change / IssueWhat to watch out for
scoped in lambda parameter list is now always a modifierIf you had a type named scoped (e.g. ref struct @scoped { ... }) and you write (scoped scoped s) => ..., the compiler may parse it differently now (as using the scoped modifier rather than type). This can lead to ambiguity.
Changes in overload resolution with Span conversionsSince more implicit conversions are added between arrays and spans, some existing overloads may now be considered, causing ambiguity or different overload to be chosen. This can change behavior in subtle ways.
field as contextual keywordBecause field is now reserved in certain contexts (inside property accessors), any existing code that declares a field or member named field may conflict. You may need to rename your field, or escape it (e.g. @field) or use this.field to clarify.

Other Enhancements / Developer Ergonomics

In addition to the above “major” features, some smaller improvements and “nice to haves”:

  • Cleaner syntax in many cases: fewer explicit types needed, more expressive lambdas etc.

  • Reduced boilerplate for properties as noted (via field) and extension members.

  • Running single file apps / scripts more easily. There is a “file-based apps” capability: you can run a standalone C# file directly with dotnet run app.cs, without creating a full project file. Useful for quick scripting, prototyping.

Examples

To illustrate, here are some mini-code snippets showing how things are simpler or better:

// Before C#14, if you needed logic in setter, you had to do this:
private string _name;
public string Name
{
    get => _name;
    set
    {
        if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException();
        _name = value.Trim();
    }
}

// With C#14 you can do:
public string Name
{
    get; 
    set => field = string.IsNullOrWhiteSpace(value) ? throw new ArgumentException() : value.Trim();
}
// Lambda modifiers without explicit types:
delegate bool TryParse<T>(string text, out T result);
TryParse<int> parse = (text, out result) => int.TryParse(text, out result);
// nameof with unbound generic
Console.WriteLine(nameof(List<>)); // "List"
// user-defined compound assignment in e.g. a struct
public struct MyCounter
{
    private int _count;
    public static MyCounter operator +(MyCounter a, MyCounter b) => …;
    public static MyCounter operator +(MyCounter a, int b) => …;

    public static MyCounter operator +=(ref MyCounter a, MyCounter b) 
    {
        // now you can define this operator to modify a in place
        a._count += b._count;
        return a;
    }
}


Practical Implications / When to Use Which Feature

These features are particularly useful in the following scenarios:

  • Performance-sensitive code (memory, high throughput): Span/ReadOnlySpan implicit conversions help reduce copying; compound assignment operators in value types can reduce allocations.

  • Code generation / source generation: Partial constructors, partial events, extension members simplify generated code by separating definition vs implementation.

  • API/library authors: New syntax makes APIs more ergonomic, allows advanced patterns. Be mindful of overloads and Span conversions.

  • Maintaining large codebases: The field keyword and null-conditional assignment help reduce boilerplate and places where subtle bugs (e.g. null checks) creep in.

C# 14 vs. C# 13 – Side-by-Side Comparison

C# 13 (with .NET 9) already brought some meaningful language features like params spans, interceptors, and collection expressions.
C# 14 (with .NET 10) focuses more on developer ergonomics and fine-tuning the language.

Feature Comparison Table

CategoryC# 13 (2024)C# 14 (2025)Why C# 14 Matters
Parameters & Lambdasparams for Span<T> and ReadOnlySpan<T> added, allowing allocation-free params arrays.Lambda parameters can now use modifiers (ref, out, in, scoped) without explicit types.Less verbose lambdas; improves functional programming style and event handling code.
PropertiesNo direct support for field references in auto-properties (you had to manually create backing fields).field contextual keyword lets you reference the compiler-generated backing field in get/set.Removes boilerplate, especially in domain models and DTOs with logic in setter.
Collection/Initializer ImprovementsCollection expressions introduced ([], [x, y, ..otherList]).No major change, but now more seamless with Span<T> conversions.C# 14 complements collection expressions by making Span use more ergonomic.
Source Generators / Meta-ProgrammingInterceptors introduced: let generated code intercept calls to existing code.Partial constructors and partial events added (in addition to partial methods/properties).Makes code generation cleaner, reduces need for reflection or manually written glue code.
Extension MembersOnly extension methods (static) allowed.Extension properties and extension members supported.Major upgrade — allows extending types with computed properties, improving readability.
nameof Improvementsnameof worked with bound generic types (nameof(List<int>)).Supports unbound generic types (nameof(List<>)).Helpful for logging, diagnostics, and source generators.
OperatorsNo user-defined compound assignment operator support (compiler always lowered += to +).You can now define custom compound assignment operators.Performance benefit for structs and domain-specific numeric types.
Null HandlingNo change from C# 12.Null-conditional assignment allowed (obj?.Property = value;).Reduces boilerplate null checks in property assignment scenarios.
Scripting / Single-File ExecutionRequired a project file or csi REPL.File-based apps: run dotnet run file.cs directly.Good for quick prototyping, teaching, automation script

Code Examples

1. Lambda Modifiers – Cleaner Syntax

C# 13

TryParse<int> parse = (string text, out int result) => int.TryParse(text, out result);

C# 14

TryParse<int> parse = (text, out result) => int.TryParse(text, out result);

2. Auto-Property Backing Field

C# 13

private int _age;
public int Age
{
    get => _age;
    set => _age = value < 0 ? 0 : value;
}

C# 14

public int Age
{
    get;
    set => field = value < 0 ? 0 : value;
}

3. Extension Properties

C# 13

// Had to use static method
public static class CustomerExtensions
{
    public static bool IsPremium(Customer c) => c.Purchases > 50;
}

C# 14

public static class CustomerExtensions
{
    public static bool IsPremium(this Customer c) => c.Purchases > 50;
    public static int LoyaltyScore(this Customer c) => c.Purchases * 10;
}

4. Compound Assignment Operator

C# 13

counter += other; // always lowered to counter = counter + other;

C# 14

public static MyCounter operator +=(ref MyCounter a, MyCounter b)
{
    a._count += b._count;
    return a;
}

This avoids extra struct copies and is more efficient.

CSharp14

Summary

C# 13 brought big new concepts like collection expressions and interceptors, which enabled new programming patterns.

C# 14 is polish + ergonomics — making everyday code cleaner, reducing boilerplate, improving performance in edge cases.

In short:

  • C# 13 = new capabilities.

  • C# 14 = refinement & productivity.

If you’re already on .NET 10, you should adopt C# 14 right away, as it’s a drop-in improvement with minimal breaking changes and good ROI for developer productivity.