This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can trysigning in orchanging directories.
Access to this page requires authorization. You can trychanging directories.
C# 13 includes the following new features. You can try these features using the latestVisual Studio 2022 version or the.NET 9 SDK:
params
collectionslock
type and semantics.\e
.ref
locals andunsafe
contexts in iterators and async methodsref struct
types to implement interfaces.partial
types.Beginning with Visual Studio 17.12, C# 13 includes thefield
contextual keyword as a preview feature.
C# 13 is supported on.NET 9. For more information, seeC# language versioning.
You can download the latest .NET 9 SDK from the.NET downloads page. You can also downloadVisual Studio 2022, which includes the .NET 9 SDK.
You can find any breaking changes introduced in C# 13 in our article onbreaking changes.
Note
We're interested in your feedback on these features. If you find issues with any of these new features, create anew issue in thedotnet/roslyn repository.
params
collectionsTheparams
modifier isn't limited to array types. You can now useparams
with any recognized collection type, includingSystem.Span<T>,System.ReadOnlySpan<T>, and types that implementSystem.Collections.Generic.IEnumerable<T> and have anAdd
method. In addition to concrete types, the interfacesSystem.Collections.Generic.IEnumerable<T>,System.Collections.Generic.IReadOnlyCollection<T>,System.Collections.Generic.IReadOnlyList<T>,System.Collections.Generic.ICollection<T>, andSystem.Collections.Generic.IList<T> can also be used.
When an interface type is used, the compiler synthesizes the storage for the arguments supplied. You can learn more in the feature specification forparams
collections.
For example, method declarations can declare spans asparams
parameters:
public void Concat<T>(params ReadOnlySpan<T> items){ for (int i = 0; i < items.Length; i++) { Console.Write(items[i]); Console.Write(" "); } Console.WriteLine();}
The .NET 9 runtime includes a new type for thread synchronization, theSystem.Threading.Lock type. This type provides better thread synchronization through its API. TheLock.EnterScope() method enters an exclusive scope. Theref struct
returned from that supports theDispose()
pattern to exit the exclusive scope.
The C#lock
statement recognizes if the target of the lock is aLock
object. If so, it uses the updated API, rather than the traditional API usingSystem.Threading.Monitor. The compiler also recognizes if you convert aLock
object to another type and theMonitor
based code would be generated. You can read more in the feature specification for thenew lock object.
This feature allows you to get the benefits of the new library type by changing the type of object youlock
. No other code needs to change.
You can use\e
as acharacter literal escape sequence for theESCAPE
character, UnicodeU+001B
. Previously, you used\u001b
or\x1b
. Using\x1b
wasn't recommended because if the next characters following1b
were valid hexadecimal digits, those characters became part of the escape sequence.
This feature makes small optimizations to overload resolution involving method groups. Amethod 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.
You can read the details of the changes in theproposal specification.
The implicit "from the end" index operator,^
, is now allowed in an object initializer expression for single-dimension collections. For example, you can now initialize a single-dimension array using an object initializer as shown in the following code:
public class TimerRemaining{ public int[] buffer { get; set; } = new int[10];}var countdown = new TimerRemaining(){ buffer = { [^1] = 0, [^2] = 1, [^3] = 2, [^4] = 3, [^5] = 4, [^6] = 5, [^7] = 6, [^8] = 7, [^9] = 8, [^10] = 9 }};
TheTimerRemaining
class includes abuffer
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
andunsafe
in iterators andasync
methodsThis feature and the following two features enableref struct
types to use new constructs. You won't use these features unless you write your ownref struct
types. More likely, you'll see an indirect benefit asSystem.Span<T> andSystem.ReadOnlySpan<T> gain more functionality.
Before C# 13, iterator methods (methods that useyield return
) andasync
methods couldn't declare localref
variables, nor could they have anunsafe
context.
In C# 13,async
methods can declareref
local variables, or local variables of aref struct
type. However, those variables can't be accessed across anawait
boundary. Neither can they be accessed across ayield return
boundary.
This relaxed restriction enables the compiler to allow verifiably safe use ofref
local variables andref struct
types in more places. You can safely use types likeSystem.ReadOnlySpan<T> in these methods. The compiler tells you if you violate safety rules.
In the same fashion, C# 13 allowsunsafe
contexts in iterator methods. However, allyield return
andyield 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 aref 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:
public class C<T> where T : allows ref struct{ // Use T as a ref struct: public void M(scoped T p) { // The parameter p must follow ref safety rules }}
This enables types such asSystem.Span<T> andSystem.ReadOnlySpan<T> to be used with generic algorithms, where applicable. You can learn more in the updates forwhere
and the programming guide article ongeneric constraints.
ref struct
interfacesBefore C# 13,ref struct
types weren't allowed to implement interfaces. Beginning with C# 13, they can. You can declare that aref struct
type implements an interface. However, to ensure ref safety rules, aref 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 aref struct
can be accessed only through a type parameter where that type parameterallows ref struct
. Also,ref struct
types must implement all methods declared in an interface, including those methods with a default implementation.
Learn more in the updates onref struct
types and the addition of theallows ref struct
generic constraint.
You can declarepartial
properties andpartial
indexers in C# 13. Partial properties and indexers generally follow the same rules aspartial
methods: you create onedeclaring declaration and oneimplementing declaration. The signatures of the two declarations must match. One restriction is that you can't use an auto-property declaration forimplementing a partial property. Properties that don't declare a body are considered thedeclaring declaration.
public partial class C{ // Declaring declaration public partial string Name { get; set; }}public partial class C{ // implementation declaration: private string _name; public partial string Name { get => _name; set => _name = value; }}
You can learn more in the article onpartial members.
In C# 13, the compiler recognizes theOverloadResolutionPriorityAttribute 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 useOverload 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.
field
keywordThefield
contextual keyword is in C# 13 as a preview feature. The tokenfield
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.
Thefield
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 namedfield
. You can use@field
orthis.field
to disambiguate between thefield
keyword and the identifier.
Important
Thefield
keyword is a preview feature in C# 13. You must be using .NET 9 and set your<LangVersion>
element topreview
in your project file in order to use thefield
contextual keyword.
You should be careful using thefield
keyword feature in a class that has a field namedfield
. The newfield
keyword shadows a field namedfield
in the scope of a property accessor. You can either change the name of thefield
variable, or use the@
token to reference thefield
identifier as@field
. You can learn more by reading the feature specification forthefield
keyword.
If you try this feature and have feedback, add it to thefeature issue in thecsharplang
repository.
Was this page helpful?
Was this page helpful?