What We Didn't Know About C# 13

Overview

C# 13, the latest iteration of the C# language, brings several powerful features that can enhance both developer productivity and application performance. Many of these features are subtle or less commonly discussed, but they are incredibly useful in building modern, efficient, and maintainable applications. In this article, we’ll uncover hidden gems in C# 13, including advanced patterns, performance enhancements, and tools to make developers' lives easier.

Pattern Matching Enhancements

Pattern matching is one of the most exciting features that have evolved in recent versions of C#. With C# 13, the pattern matching capabilities have received some powerful updates, making it even more flexible and expressive.

List Patterns

It's now possible to match against a list's structure directly. This allows us to work with collections in a more declarative way, simplifying common use cases like checking for specific patterns in lists.

In the code example below, we see that we can match a list pattern in the following way: [1, 2, 3] matches a list with the exact values 1, 2, and 3. [int x, int y, ..] matches a list that has only the first two elements as integers and ignores the others. Finally, the pattern [.., int z] matches a list where the last element is an integer, allowing for flexible and expressive matching of list structures in C#.

The file name is PatternMatching.cs

namespace CSharp13Features.PatternMatching;

public static class PatternMatching
{
    public static string MatchListPattern(List<int> numbers)
    {
        return numbers switch
        {
        [1, 2, 3] => "We have found 1, 2, and 3",
        [int x, int y, ..] => $"We have found first two numbers: {x} and {y}",
        [.., int z] => $"The Last number we have found is {z}",
            _ => "The Pattern not matched sorry !"
        };
    }
}
//Program.cs
PatternMatching.MatchListPattern(new List<int> { 1, 2, 3, 4, 5 });

This allows us to easily decompose lists and arrays, improving code readability and maintainability.

Property Patterns

As shown in the code example below, C# 13 makes it easier to match against object properties directly in switch expressions or if statements. By using property patterns, we can match directly against object properties, resulting in more concise and intuitive code.

The File is Person.cs found in Models Folder.

namespace CSharp13Features.Models;
public class Person
{
    public Guid Id { get; set; }
    public string FirstName { get; set; }=string.Empty;
    public string LastName { get; set; } = string.Empty;
    public string EmailAddress { get; set; } = string.Empty;
    public int Age { get; set; }
    public string FullName => $"{FirstName} {LastName}";
}

Add the following code below in PatternMataching.cs file

namespace CSharp13Features.PatternMatching;

public static class PatternMatching
{
    public static string MatchPerson(Person person)
    {
        return person switch
        {
            { FirstName: "Lisa", Age: 30 } => "Lisa  is 28 years old",
            { Age: < 18 } => "Underage person",
            { FullName: var fullName } => $"Person's name is {fullName}",
            _ => "Unknown person"
        };
    }
}
//Program.cs 
PatternMatching.MatchPerson(new Person { FirstName = "Lisa", LastName="Joe", EmailAddress="[email protected]", Age = 30 });

Performance Enhancements

There are various performance enhancements introduced with C# 13 that focus on reducing overhead and increasing execution speed, which is crucial when building high-performance applications using C#13.

Stack-Only Structs

With C# 13, structs that live only on the stack can be defined. Because stack-only structs avoid heap allocation, they are optimized for performance and memory allocation, making them more lightweight. As shown in the code example below, the struct StackOnlyStruct is allocated on the stack, which eliminates garbage collection and avoids heap-based memory management overhead. Performance-critical scenarios, such as high-frequency trading systems or real-time applications, can benefit from this.

 The file name is StackOnlyStruct.cs found in folder name Structs.

namespace CSharp13Features.Structs;
public readonly struct StackOnlyStruct
{
    public int X { get; }

    public StackOnlyStruct(int x)
    {
        X = x;
    }
}

The file name is Performances.cs found at the root of the project.

namespace CSharp13Features;
public class Performances
{
    public static void ProcessStackOnlyStruct()
    {
        var stackStruct = new StackOnlyStruct(10);
        Console.WriteLine(stackStruct.X);
    }

}

Improved Method Inlining

Enhanced method inlining capabilities are offered in C# 13 through the Just-In-Time (JIT) compiler. Simple methods are automatically inlined, reducing the overhead of method calls and improving performance. For example, AddNumbers and MultiplyNumbers can be inlined by the JIT compiler, effectively removing call overhead and significantly improving execution speed, especially in performance-critical scenarios, such as tight loops or frequently invoked functions. In the code example below shows a simple methods of AddNumbers and MultiplyNumbers to show the improved method inlining feature of C#13.

namespace CSharp13Features;
public class Performances
{
    public static void ProcessStackOnlyStruct()
    {
        var stackStruct = new StackOnlyStruct(10);
        Console.WriteLine(stackStruct.X);
    }

    public int AddNumbers(int a, int b) => a + b;

    public int MultiplyNumbers(int a, int b) => a * b;

}
//Program.cs

Performances.ProcessStackOnlyStruct();

Performances performances = new Performances();
performances.AddNumbers(28, 30);
performances.MultiplyNumbers(313, 154);

Nullable Enable/Disable for Specific Regions

Another powerful productivity tool introduced in C# 13 is the ability to enable or disable nullable reference types for specific regions of code. This gives developers the flexibility to manage nullability on a granular level, especially when working with legacy code or third-party libraries.

Enabling/Disabling Nullable Contexts

The #nullable enable and #nullable disable directives in C# 13 allow developers to control nullability at a granular level by enabling or disabling nullability checks for specific code areas. By offering this flexibility, code developers can handle sections of their codebase that don't strictly adhere to nullable reference types without having to disable nullability checks throughout the whole project, as shown in the following code example:

The File name is Nullables.cs found at the root of the project.

namespace CSharp13Features;
public class Nullables
{
    #nullable enable
    public string? Details { get; set; }

    #nullable disable
    public string GetNonNullableString()
    {
        return "Hi This is no Nullable"; // Here there is no nullable warning.
    }
}
//Program.cs
Nullables nullables = new Nullables();

Console.WriteLine(nullables.Detials);
Console.WriteLine(nullables.GetNonNullableString());

Global Using Directives

Now we are going to use in all files in the project can use System, System.Collections.Generic, and System.Linq without explicitly importing these namespaces.

//GlobalUsing.cs
global using System;
global using System.Collections.Generic;
global using CSharp13Features;
global using CSharp13Features.Models;
global using CSharp13Features.PatternMatching;
global using CSharp13Features.Structs;

Enhancements in Records and Tuples

To simplify development and improve performance, C# 13 has significantly improved records and tuples, emphasizing lightweight data structures and immutability. With the addition of new features, records are now more versatile and efficient in scenarios requiring immutability and value-based equality. As a result, tuples now offer a more intuitive and expressive way to handle multiple related values, reducing the need for custom data types. As a result of these advances, developers can write cleaner, more maintainable code while optimizing performance and simplicity.

Record Structs

With C# 13, record types are enhanced to include record structs. As a result, we can define immutable structures that support value-based equality, making them ideal for performance-sensitive applications. In this code example below, Point is a record struct, and == comparison is supported by default for value-based equality.

//Points.cs

namespace CSharp13Features.Structs;
public readonly record struct Point(int X, int Y);
//Program.cs

Point pointOne = new Point(50, 20);
Point pointTwo = new Point(80, 10);
Console.WriteLine(pointOne == pointTwo);

Enhanced Tuples

In C# 13, tuples can be used in a more advanced manner, which allows us to pack and return multiple values in a concise and expressive way, as shown in the code example below.

namespace CSharp13Features;
public  class Tuples
{
    public static void DeconstructTuple()
    {
        var tuple = (1, "Dummay Eample");
        var (number, word) = tuple;
        Console.WriteLine($"{number}, {word}");
    }

}

Other Notable Features in C# 13


Improvements to Source Generators

In C# 13, source generators have been improved, a feature introduced in C# 9. These generators allow developers to generate code during the compilation process, automating repetitive tasks and improving performance. This is highly recommended to speed up the software development.

Improvements to Lambda Expressions

C# 13 introduces more advanced lambda features, including lambda functions that can return multiple values. This can significantly simplify scenarios where we'd normally need to create helper classes or methods.

namespace CSharp13Features;

public class Numbers
{
    public static string CalculateHardwired()
    {
        Func<int, int, (int sum, int product)> calculate = (a, b) => (a + b, a * b);
        
        var result = calculate(47, 13);
        
        return $"Total: {result.sum}, Product: {result. Product}";
    }
}

Summary

C# 13 introduces a range of exciting new features that can make our code more expressive, efficient, and maintainable. From advanced pattern matching to performance enhancements and productivity tools like global using directives and nullable context management, there are many improvements to explore. By incorporating these features into our daily development workflow, we can write cleaner, faster, and more powerful applications.

I am currently writing the book title Unlocking .NET 9 and C# 13: Cutting-Edge Features and Best Practices, which will be published in the coming weeks on C# Corner. I highly recommend reading it to gain further understanding and knowledge of C#13 features.

The code examples for this article are on my GitHub Repository: https://github.com/ziggyrafiq/CSharp13Features  and if you like my articles here please do follow me on GitHub and LinkedIn: https://www.linkedin.com/in/ziggyrafiq/ as your support means a lot to me.  

Below is the complete Program.cs code for this article. Happy Coding ๐Ÿ˜Š

//Program.cs

Console.WriteLine("Hello, from Ziggy Rafiq welcome to Article What We Didn't Know About C# 13!");

PatternMatching.MatchListPattern(new List<int> { 1, 2, 3, 4, 5 });

PatternMatching.MatchPerson(new Person { FirstName = "Lisa", LastName="Joe", EmailAddress="[email protected]", Age = 30 });

Performances.ProcessStackOnlyStruct();

Performances performances = new Performances();
performances.AddNumbers(28, 30);
performances.MultiplyNumbers(313, 154);

Nullables nullables = new Nullables();

Console.WriteLine(nullables.Detials);
Console.WriteLine(nullables.GetNonNullableString());

Point pointOne = new Point(50, 20);
Point pointTwo = new Point(80, 10);
Console.WriteLine(pointOne == pointTwo);

Tuples.DeconstructTuple();

Console.WriteLine(Numbers.CalculateHardwired());

 


Similar Articles
Capgemini
Capgemini is a global leader in consulting, technology services, and digital transformation.