C#  

C# Programming Language Guide

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

VersionYear.NET PlatformMilestone Features
C# 1.02002.NET 1.0Classes, interfaces, delegates, events
C# 2.02005.NET 2.0Generics, iterators, nullable types, anonymous methods
C# 3.02007.NET 3.5LINQ, lambda expressions, extension methods
C# 4.02010.NET 4.0Dynamic binding, named/optional parameters
C# 5.02012.NET 4.5async/await, caller info attributes
C# 6.02015.NET 4.6Null-conditional operator, string interpolation
C# 7.x2017–18.NET 4.7 / Core 2.xPattern matching, tuples, local functions
C# 8.02019.NET Core 3.0Nullable reference types, async streams
C# 9.02020.NET 5Records, init-only setters, top-level programs
C# 10.02021.NET 6Global usings, file-scoped namespaces
C# 11.02022.NET 7Raw string literals, required members
C# 12.02023.NET 8Primary constructors, collection expressions
C# 13.0Nov 2024.NET 9params collections, new lock type, ref struct interfaces
C# 14.0Nov 2025.NET 10Extension 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

FeatureVersionPerformance Impact
params ReadOnlySpan<T>C# 13Avoids heap allocation vs. array-based params
New  Lock  typeC# 13Reduced overhead vs. Monitor for uncontended locks
ref struct  interfacesC# 13Generic algorithms on stack-allocated types
allows ref structC# 13Stack allocation in more generic contexts
Implicit Span conversionsC# 14Reduces unnecessary allocation at call sites
User-defined compound operatorsC# 14In-place mutation without copies

SECTION 05

Tooling & Ecosystem

SDK and IDE Requirements

C# VersionSDK RequiredMinimum VS 2022VS Code
C# 13.NET 9 SDKVersion 17.12C# Dev Kit 1.x
C# 14.NET 10 SDKVersion 17.14C# 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.