You can find any breaking changes introduced in C# 13 in our article on breaking changes.
Note
We're interested in your feedback on these features. If you find issues with any of these new features, create a new issue in the dotnet/roslyn repository.
When an interface type is used, the compiler synthesizes the storage for the arguments supplied. You can learn more in the feature specification for params collections.
For example, method declarations can declare spans as params parameters:
C#
publicvoid Concat<T>(params ReadOnlySpan<T> items)
{
for (int i = 0; i < items.Length; i++)
{
Console.Write(items[i]);
Console.Write(" ");
}
Console.WriteLine();
}
New lock object
The .NET 9 runtime includes a new type for thread synchronization, the System.Threading.Lock type. This type provides better thread synchronization through its API. The Lock.EnterScope() method enters an exclusive scope. The ref struct returned from that supports the Dispose() pattern to exit the exclusive scope.
The C# lock statement recognizes if the target of the lock is a Lock object. If so, it uses the updated API, rather than the traditional API using System.Threading.Monitor. The compiler also recognizes if you convert a Lock object to another type and the Monitor based code would be generated. You can read more in the feature specification for the new lock object.
This feature allows you to get the benefits of the new library type by changing the type of object you lock. No other code needs to change.
New escape sequence
You can use \e as a character literal escape sequence for the ESCAPE character, Unicode U+001B. Previously, you used \u001b or \x1b. Using \x1b wasn't recommended because if the next characters following 1b were valid hexadecimal digits, those characters became part of the escape sequence.
Method group natural type
This feature makes small optimizations to overload resolution involving method groups. A method group is a method and all overloads with the same name. The previous behavior was for the compiler to construct the full set of candidate methods for a method group. If a natural type was needed, the natural type was determined from the full set of candidate methods.
The new behavior is to prune the set of candidate methods at each scope, removing those candidate methods that aren't applicable. Typically, the removed methods are generic methods with the wrong arity, or constraints that aren't satisfied. The process continues to the next outer scope only if no candidate methods are found. This process more closely follows the general algorithm for overload resolution. If all candidate methods found at a given scope don't match, the method group doesn't have a natural type.
The implicit "from the end" index operator, ^, is now allowed in an object initializer expression. For example, you can now initialize an array in an object initializer as shown in the following code:
The TimerRemaining class includes a buffer array initialized to a length of 10. The preceding example assigns values to this array using the "from the end" index operator (^), effectively creating an array that counts down from 9 to 0.
In versions before C# 13, the ^ operator can't be used in an object initializer. You need to index the elements from the front.
ref and unsafe in iterators and async methods
This feature and the following two features enable ref struct types to use new constructs. You won't use these unless you write your own ref struct types. More likely, you'll see an indirect benefit as System.Span<T> and System.ReadOnlySpan<T> gain more functionality.
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.
In C# 13, async methods can declare ref local variables, or local variables of a ref struct type. However, those variables can't be accessed across an await boundary. Neither can they be accessed across a yield return boundary.
This relaxed restriction enables the compiler to allow verifiably safe use of ref local variables and ref struct types in more places. You can safely use types like System.ReadOnlySpan<T> in these methods. The compiler tells you if you violate safety rules.
In the same fashion, C# 13 allows unsafe contexts in iterator methods. However, all yield return and yield break statements must be in safe contexts.
allows ref struct
Before C# 13, ref struct types couldn't be declared as the type argument for a generic type or method. Now, generic type declarations can add an anti-constraint, allows ref struct. This anti-constraint declares that the type argument supplied for that type parameter can be a ref struct type. The compiler enforces ref safety rules on all instances of that type parameter.
For example, you might declare a generic type like the following code:
C#
publicclassC<T> whereT : allowsrefstruct
{
// Use T as a ref struct:publicvoidM(scoped T p)
{
// The parameter p must follow ref safety rules
}
}
Before C# 13, ref struct types weren't allowed to implement interfaces. Beginning with C# 13, they can. You can declare that a ref struct type implements an interface. However, to ensure ref safety rules, a ref struct type can't be converted to an interface type. That conversion is a boxing conversion, and could violate ref safety. Explicit interface method declarations in a ref struct can be accessed only through a type parameter where that type parameter allows ref struct. Also, ref struct types must implement all methods declared in an interface, including those methods with a default implementation.
You can declare partial properties and partial indexers in C# 13. Partial properties and indexers generally follow the same rules as partial methods: you create one declaring declaration and one implementing declaration. The signatures of the two declarations must match. One restriction is that you can't use an auto-property declaration for implementing a partial property. Properties that don't declare a body are considered the declaring declaration.
C#
publicpartialclassC
{
// Declaring declarationpublicpartialstring Name { get; set; }
}
publicpartialclassC
{
// implementation declaration:privatestring _name;
publicpartialstring Name
{
get => _name;
set => _name = value;
}
}
In C# 13, the compiler recognizes the OverloadResolutionPriorityAttribute to prefer one overload over another. Library authors can use this attribute to ensure that a new, better overload is preferred over an existing overload. For example, you might add a new overload that's more performant. You don't want to break existing code that uses your library, but you want users to update to the new version when they recompile. You can use Overload resolution priority to inform the compiler which overload should be preferred. Overloads with the highest priority are preferred.
This feature is intended for library authors to avoid ambiguity when adding new overloads. Library authors should use care with this attribute to avoid confusion.
The field keyword
The field contextual keyword is in C# 13 as a preview feature. The token field accesses the compiler synthesized backing field in a property accessor. It enables you to write an accessor body without declaring an explicit backing field in your type declaration. You can declare a body for one or both accessors for a field backed property.
The field feature is released as a preview feature. We want to learn from your experiences using it. There's a potential breaking change or confusion reading code in types that also include a field named field. You can use @field or this.field to disambiguate between the field keyword and the identifier.
Important
The field keyword is a preview feature in C# 13. You must be using .NET 9 and set your <LangVersion> element to preview in your project file in order to use the field contextual keyword.
You should be careful using the field keyword feature in a class that has a field named field. The new field keyword shadows a field named field in the scope of a property accessor. You can either change the name of the field variable, or use the @ token to reference the field identifier as @field. You can learn more by reading the feature specification for the field keyword.
If you try this feature and have feedback, add it to the feature issue in the csharplang repository.
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, see our contributor guide.
.NET feedback
.NET is an open source project. Select a link to provide feedback:
Learn how to implement read-write, read-only, and write-only class properties using property accessors and access modifiers, and how to implement methods and extension methods for a class.