- Home
- .NET tutorials
- C# 13 - New features and how you can use them now!
C# 13 - New features and how you can use them now!
Published: Monday 18 November 2024
C# 13 has been launched as part of the .NET 9 release and we'll take a look at the new features that you can use right now.
As well as that, we'll guide you on how you start using C# 13, even if you don't want to update your ASP.NET Core application to .NET 9.
New features
Here are the new features that are included in C# 13:
params
collections
Traditionally, you could only use the params
modifier on arrays. But this has been extended to a range of collection types, such as a Span
, a ReadOnlySpan
and any collection type that implements the IEnumerable
interface and has an Add
method.
C# coding challenges
This example uses the params
modifier with a List
and returns it.
public static class ParamsCollections
{
public static List<int> ReadMyNumbers(params List<int> numbers)
{
return numbers;
}
}
New lock object
There is a new lock type in C# which can be found in System.Threading.Lock
. Microsoft claim that it "provides better thread synchronisation through its API".
The lock
statement recognises if it uses the new Lock
object based on the instance type that is passed in as the parameter. If it's using the newLock
object, the updated API is used rather than the traditional API which uses System.Threading.Monitor
.
Here is an example of the new Lock
object:
public static class NewLock
{
public static Lock _lock = new Lock();
public static async Task EnteringMyLock()
{
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"Thread ID: {threadId} - Waiting for lock to open");
lock (_lock)
{
Console.WriteLine($"Thread ID: {threadId} - Entered the lock");
Console.WriteLine($"Thread ID: {threadId} - Exiting the lock");
}
await Task.CompletedTask;
}
}
New escape sequence
Before C# 13, the escape sequence would be written as \u001b
. You could also write it as \x1b
although that wasn't recommended.
Now you can simply write it as \e
.
Implicit index access
The "from the end" index operator ^
is now allowed in object initialiser expressions.
In this example, we have created an ImplicitIndexAccess
class with a Numbers
property which has an integer array with a length of 5.
We can now initialise the Numbers
property when we initalise ImplicitIndexAccess
class and use the "from the end" index operator to populate the array values.
public class ImplicitIndexAccess
{
public int[] Numbers { get; set; } = new int[5];
}
var implicitIndexAccess = new ImplicitIndexAccess()
{
Numbers =
{
[^1] = 5,
[^2] = 4,
[^3] = 3,
[^4] = 2,
[^5] = 1
}
};
^1
means the last one, ^2
means the second to last one, and so on. So the Numbers
property array will be populated as 1
, 2
, 3
, 4
, 5
.
ref
and unsafe
in iterators and async
methods
Before C# 13, iterator methods (methods that use yield return
) and async
methods couldn't declare local ref
variables, nor could they have an unsafe
context.
But now they can. However, these variables can't be accessed across an await
boundary or a yield return
boundary.
Here is an example of creating a local reference using the MyMessage
static string and appending "Hello there"
to the message.
public static class RefInIteratorsAndAsyncMethods
{
public static string MyMessage = string.Empty;
public static async Task AddMessage()
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
ref var myMessage = ref GetMyMessage();
AddToMyMessage(ref myMessage, "Hello there");
}
private static ref string GetMyMessage()
{
return ref MyMessage;
}
private static void AddToMyMessage(ref string message, string theMessage)
{
message += theMessage;
}
}
allows ref struct
ref struct
types can now be declared as a generic type or method. You have to add allows ref struct
in the generic where
clause for this to work as this example demonstrates.
public class AllowsRefStruct<TRef> where TRef : allows ref struct
{
}
public ref struct IsValid
{
public bool Valid { get; set; }
}
ref struct
interfaces
Staying on the theme of ref struct
types, they can now implement interfaces as this example proves.
public ref struct RefStructInterfaces : IInterface
{
}
public interface IInterface { }
Partial properties and indexers
There are more partial members with the introduction of partial properties and indexers.
For this to work, you have to add the declaration into one of the partial classes and the implementation into another partial class with the same name and namespace.
public partial class MorePartialMembers
{
// Declaration
public partial string? Surname { get; set; }
public partial string this[int x] { get; set; }
}
public partial class MorePartialMembers
{
// Implementation
private string? _surname;
public partial string? Surname
{
get => _surname;
set => _surname = value;
}
public partial string this[int x] { get => "Hello"; set { } }
}
Partial members are useful in code generation tools where the tool will declare the members and you can add your own implementation. Read more about how partial classes work.
How to use C# 13
To use C# 13, you'll need to download the .NET 9 SDK. From there, you can either update your .NET application to .NET 9, or set the LangVersion
attribute in your .csproj
file.
Not updating to .NET 9
If you don't want to update your application to .NET 9, you can either set the LangVersion
attribute to either latest
, latestMajor
, default
, or specify the C# version number which is 13.0
.
Here's an example of a .NET 8 project using C# 13:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>13.0</LangVersion>
</PropertyGroup>
</Project>
Not all features will work below .NET 9
If you are not updating your application to .NET 9, then the new lock object will not work. This is because the Lock
object is in the .NET 9 source code.
Additionally, you can't use a ref struct
as a generic type below .NET 9 as it's not supported in the runtime.
Watch the new features demonstration
Watch our new features demonstration video where we go through each new feature and show you how to implement them.
You can also download the code example which contains each of these new features for you to try.