Modern C# Features Every .NET Developer Should Know

Modern C# Features Every .NET Developer Should Know

(Updated: )

Modern C# Features Every .NET Developer Should Know

C# continues to evolve as one of the most powerful and developer-friendly programming languages in the world. With every annual release, Microsoft adds features that make writing clean, efficient, and modern code much easier.

In this article, we'll summarize the features across recent C# versions (12 through the current 14) that every .NET developer should know. Whether you're building enterprise applications, APIs, or cloud-native solutions, these updates will help you write less code, improve performance, and reduce bugs.


đź“– Table of Contents


Which C# version introduced what?

Feature C# Version .NET Version
Primary constructors for classes/structs C# 12 .NET 8
Collection expressions ([1, 2, 3]) C# 12 .NET 8
Inline array literals for Span<T> C# 12 .NET 8
Default lambda parameters C# 12 .NET 8
Interceptors (preview) C# 12 .NET 8
params collections (not just arrays) C# 13 .NET 9
New Lock type / lock-statement pattern C# 13 .NET 9
Implicit index access in object initializers C# 13 .NET 9
field keyword for auto-properties (stable) C# 14 .NET 10
Extension members (extension blocks) C# 14 .NET 10
Null-conditional assignment (?. on the left of =) C# 14 .NET 10
First-class span conversions C# 14 .NET 10

The sections below cover the C# 12-era features this post originally focused on, followed by what's new in C# 13 and C# 14.


1. C# Primary Constructors for Classes

C# now supports primary constructors directly in classes (earlier available only for records). This reduces boilerplate and makes class initialization more concise.

public class Product(string name, decimal price)
{
    public string Name { get; } = name;
    public decimal Price { get; } = price;
}

âś… No need to write manual constructors.
âś… Great for immutable data models.


2. C# Collection Expressions Example

C# introduces collection expressions to make working with arrays and collections much cleaner.

int[] numbers = [1, 2, 3, 4, 5];
List<string> names = ["Alice", "Bob", "Charlie"];

This is similar to JavaScript or Python syntax and improves readability.


3. Inline Array Literals and Span<T> in C#

Performance-focused developers will love this. You can now initialize Span<T> and ReadOnlySpan<T> using inline array literals.

Span<int> values = [1, 2, 3, 4];
ReadOnlySpan<char> letters = ['a', 'b', 'c'];

This avoids unnecessary allocations and is great for high-performance applications.


4. Using Directives and Aliases in C#

You can simplify code organization with file-scoped using directives and aliases.

global using System.Text.Json;
using ProjectModels = MyApp.Core.Models;

âś… Helps manage namespaces in large projects.


5. C# Interceptors (Preview Feature)

Interceptors allow you to inject logic before a method call executes, making it possible to customize APIs and behaviors without modifying the original method.

[InterceptsLocation("MyFile.cs", 25, 10)]
public static void InterceptDoSomething()
{
    Console.WriteLine("Intercepted!");
}

đź’ˇ Think of it as a compile-time AOP (Aspect-Oriented Programming) feature.

⚠️ Interceptors remain a preview-only feature through C# 13/.NET 9 - they're primarily meant to be emitted by source generators (e.g. for compile-time interception of specific call sites) rather than hand-written in application code, and the feature still requires an explicit opt-in MSBuild property (InterceptorsPreviewNamespaces or similar, depending on SDK version). Don't rely on this for production code paths without checking the current preview status for the SDK version you're targeting.


6. Enhanced Pattern Matching in C#

C# keeps expanding its pattern matching capabilities, making code more expressive and readable.

if (obj is Product { Price: > 100 and < 500 })
{
    Console.WriteLine("Mid-range product");
}

âś… Cleaner than nested if conditions.


7. Default Lambda Parameters in C#

Lambda expressions can now have default parameter values, improving flexibility.

Func<int, int, int> add = (a, b = 10) => a + b;

Console.WriteLine(add(5));    // 15
Console.WriteLine(add(5, 20)); // 25

8. Improvements in nameof Operator

The nameof operator now works with method parameters more intuitively, helping with logging, exception handling, and diagnostics.

void ProcessOrder(int orderId)
{
    if (orderId <= 0)
        throw new ArgumentException($"Invalid {nameof(orderId)}");
}

9. Raw String Literals in C#

Working with JSON, SQL, or multiline text is now much easier with raw string literals.

string query = """
    SELECT * 
    FROM Products
    WHERE Price > 100
    ORDER BY Name;
    """;

âś… No need for escape sequences.
âś… Makes code more readable.


10. Performance-Oriented Features in C#

  • Optimized foreach loops for better iteration performance.
  • Reduced memory allocations in many BCL (Base Class Library) APIs.
  • Better JIT optimizations in .NET runtime for modern processors.

These features make C# one of the fastest managed languages for enterprise and cloud-scale applications.


11. What's New in C# 13

C# 13 (shipped with .NET 9) added a smaller, more incremental set of features compared to C# 12, but a few are worth adopting immediately:

// params collections - not just T[] anymore
void LogAll(params IEnumerable<string> messages) { /* ... */ }
LogAll("one", "two", "three");          // still works
LogAll(["one", "two", "three"]);        // also works - any collection type, not just arrays

// New Lock type - a lighter, faster alternative to `lock (object)`
private readonly Lock _lock = new();
lock (_lock)
{
    // the compiler recognizes System.Threading.Lock and emits a more efficient
    // acquire/release pattern than the classic Monitor-based lock(object)
}

// Implicit index access in object initializers
int[] years = new int[4];
var config = new SomeType
{
    Values = { [^1] = 2026 }  // ^1 (from-the-end index) now works inside an initializer
};

params collections in particular is worth adopting broadly - any existing params T[] API becomes more flexible for callers without you changing its signature to something exotic, and the new Lock type is a drop-in win for any hot synchronization path.


12. What's New in C# 14

C# 14 (shipped with .NET 10, the current LTS release) is a bigger jump, with two headline features:

Extension members - a new extension block syntax that lets you add not just methods, but also properties and static members, to an existing type - something classic extension methods never supported:

public static class StringExtensions
{
    extension(string s)
    {
        public bool IsPalindrome => s.SequenceEqual(s.Reverse());
        public static string Empty => string.Empty;
    }
}

"level".IsPalindrome; // true - reads like a real property, not a method call

Null-conditional assignment - you can now use ?. on the left-hand side of an assignment, so you no longer need a separate null check before setting a property:

// before C# 14
if (customer != null)
{
    customer.LastLogin = DateTime.UtcNow;
}

// C# 14
customer?.LastLogin = DateTime.UtcNow;

A couple of smaller but useful additions round out C# 14:

  • The field keyword (preview since C# 13) is now stable, letting you add logic to an auto-property's getter/setter without declaring a full backing field: public string Name { get => field; set => field = value?.Trim(); }.
  • First-class span conversions make Span<T>/ReadOnlySpan<T> participate in overload resolution and implicit conversions more consistently with arrays, reducing the number of places you need explicit casts when working with the Span<T> APIs introduced back in C# 12/.NET 8 (see section 3 above).

Final Thoughts

C# is no longer just a “Windows-only” language—it’s now a modern, cross-platform, cloud-ready powerhouse. With features like primary constructors, collection expressions, extension members, and null-conditional assignment, developers can write cleaner and more efficient code than ever before.

👉 If you’re a .NET developer, mastering these features across C# 12 through C# 14 will set you apart and keep your skills future-proof.


📌 Key Takeaways

  • Write less boilerplate with primary constructors and the stable field keyword.
  • Boost performance using Span<T>, inline literals, and first-class span conversions.
  • Improve readability with collection expressions, raw string literals, and extension members.
  • Simplify null-checks with null-conditional assignment, and synchronization with the new Lock type.

🚀 What’s Next?

If you’re interested in learning more:

  • Explore the official .NET Blog.
  • Try these features in your .NET 9 / .NET 10 projects - .NET 10 is the current LTS release.

Once you're comfortable with the language-level features above, a natural next step is seeing how they show up in the ASP.NET Core framework code itself. I've written a series digging into that internals from the ground up:


Thanks for reading! If you found this useful, consider sharing it with your developer community to spread the word about the latest C# features.