Sponsored
- Boost your .NET development with dotConnect â ADO.NET data providers for the major databases and popular cloud services. It offers reliable updates, expert developer support, and full compatibility with ORMs like EF Core, Dapper, NHibernate, LinqConnect, etc.
Join Devartâs Black Friday sale to get 30% OFF. Join Devartâs Black Friday sale to get 30% OFF.
- Tired of outdated API documentation holding your team back? Postman simplifies your life by automatically syncing documentation with your API updates
- no more static docs, no more guesswork! Read more.
Many thanks to the sponsors who make it possible for this newsletter to be free for readers.
Want to reach thousands of .NET developers? Sponsor TheCodeMan â
The Background
C# 13 continues the evolution of Microsoftâs flagship programming language, introducing a range of features aimed at improving code expressiveness, developer productivity, and overall performance. This text explores five impactful features of C# 13, compares them with prior versions (C# 12), and explains why these additions are game-changers for developers.
1. Enhanced params Collections
Whatâs New in C# 13?
Traditionally, the params keyword allowed methods to accept a variable number of arguments, but it was limited to arrays.
With C# 13, params can now be applied to any collection type, such as List
Example in C# 13:
public void PrintNumbers(params List<int> numbers){ foreach (var number in numbers) { Console.WriteLine(number); }}Â // UsagePrintNumbers(new List<int> { 1, 2, 3 });
How It Was Done in C# 12:
public void PrintNumbers(params int[] numbers){ foreach (var number in numbers) { Console.WriteLine(number); }}Â // UsagePrintNumbers(1, 2, 3); // Could only use arrays directly.
Why Itâs Useful: The flexibility of params collections allows developers to use more versatile and modern collection types, avoiding unnecessary array conversions and simplifying APIs.
2. The New System.Threading.Lock
Whatâs New in C# 13?
C# 13 introduces the System.Threading.Lock type, a streamlined way to synchronize access to shared resources. The new Lock.EnterScope() method makes the critical section easier to manage, leveraging the Dispose pattern to automatically release the lock.
Example in C# 13:
Lock myLock = new Lock();using (myLock.EnterScope()){ // Critical section Console.WriteLine("Thread-safe code here.");}
How It Was Done in C# 12:
private static readonly object _lock = new object();Â void ThreadSafeMethod(){ lock (_lock) { // Critical section Console.WriteLine("Thread-safe code here."); }}
Why Itâs Useful: The new Lock type reduces boilerplate code and minimizes the risk of forgetting to release the lock, preventing deadlocks and improving code clarity.
3. The New Escape Sequence \e
Whatâs New in C# 13?
C# 13 introduces the escape sequence \e to represent the ESCAPE character. This addition is particularly beneficial for terminal-based applications that rely on ANSI escape codes for formatting.
Example in C# 13:
Console.WriteLine("\e[1mThis is bold text\e[0m");
How It Was Done in C# 12: In previous versions, developers had to use hardcoded values or char codes:
Console.WriteLine("\x1b[1mThis is bold text\x1b[0m");
Why Itâs Useful: The \e escape sequence improves readability and reduces errors when working with ANSI codes, making terminal-based development more accessible.
4. Implicit Index Access in Object Initializers
Whatâs New in C# 13?
C# 13 enhances object initializers by allowing implicit "from the end" index operators (^). This feature simplifies operations on collections by enabling intuitive access to the last elements.
Example in C# 13:
var numbers = new int[5] { 1, 2, 3, 4, 5 };var initializer = new List<int> { [^1] = 10 }; // Sets the last element to 10
How It Was Done in C# 12:
var numbers = new int[5] { 1, 2, 3, 4, 5 };var initializer = new List<int> { 1, 2, 3, 4, 5 };initializer[initializer.Count - 1] = 10; // Manually set the last element.
Why Itâs Useful: Implicit indexing makes code cleaner and less error-prone, reducing the likelihood of off-by-one mistakes in array and list manipulation.
5. Support for ref and unsafe in Async Methods and Iterators
Whatâs New in C# 13?
C# 13 allows ref locals and unsafe code in async methods and iterators. Previously, these features were restricted in asynchronous contexts.
Example in C# 13:
public async Task ProcessDataAsync(){ Span<byte> buffer = stackalloc byte[1024]; // Unsafe context await Task.Delay(1000);}
How It Was Done in C# 12: This was not supported directly. Developers had to split logic into separate synchronous methods:
void ProcessData(){ Span<byte> buffer = stackalloc byte[1024]; // Unsafe context}Â // Asynchronous wrapperpublic async Task ProcessDataAsync(){ await Task.Run(() => ProcessData());}
Why Itâs Useful: This feature streamlines asynchronous programming by allowing low-level memory manipulation and unsafe code directly in async methods, improving performance and reducing code fragmentation.
For earlier features, see 5 Features in C# 12 and Source Generators Deep Dive.
Wrapping Up
C# 13 introduces a powerful set of features that simplify code, enhance expressiveness, and improve performance.
Whether you're working with advanced threading, terminal applications, or asynchronous methods, these enhancements make C# 13 a significant step forward.
By comparing these new features with their counterparts in C# 12, it's clear that C# 13 reduces boilerplate code, minimizes errors, and empowers developers to write cleaner, more efficient applications.
If you havenât started exploring C# 13 yet, now is the perfect time to dive in!
That's all from me today.Â
See ya on the next Monday coffee.Â
Want to enforce clean code automatically? My Pragmatic .NET Code Rules course shows you how to set up analyzers, CI quality gates, and architecture tests - a production-ready system that keeps your codebase clean without manual reviews. Or grab the free Starter Kit to try it out.





