C# 13 and C# 14: Locks and Field-Backed Properties
Recent C# language roadmaps introduce major improvements to developer
ergonomics and runtime efficiency, spotlighting dedicated lock objects
and field-backed properties. While C# 13 officially updates the
lock statement to utilize a high-performance
synchronization primitive in .NET 9, the long-awaited field
keyword for semi-auto-implemented properties was introduced as a preview
feature in C# 13 and targeted for general release in C# 14. Together,
these features streamline codebases by removing redundant boilerplate
fields and modernizing thread synchronization.
Modern Lock Objects in C# 13
Before C# 13, thread synchronization using the lock
statement relied on System.Threading.Monitor under the
hood. Developers routinely instantiated generic object
instances purely to act as synchronization tokens:
private readonly object _syncRoot = new();
public void Process()
{
lock (_syncRoot)
{
// Critical section
}
}This pattern carried drawbacks, including potential overhead and the lack of type safety, as any reference type could be locked, leading to potential deadlocks.
C# 13 and .NET 9 introduce the System.Threading.Lock
type. The C# 13 compiler natively recognizes this type when used inside
a lock statement:
private readonly System.Threading.Lock _lock = new();
public void Process()
{
lock (_lock)
{
// Critical section
}
}When the compiler detects a System.Threading.Lock
instance, it alters its code generation. Instead of calling
Monitor.Enter and Monitor.Exit, it invokes
_lock.EnterScope(). This method returns a
ref struct that implements a Dispose method,
exiting the lock automatically when execution leaves the block. This
specialized pattern avoids allocation, achieves faster acquisition
times, and enables companion code analyzers to warn developers if a
Lock object is cast to object or misused.
Field-Backed Properties in C# 13 and C# 14
For years, developers have faced an all-or-nothing dilemma with
properties: use concise auto-implemented properties
(public string Name { get; set; }), or manually declare a
private backing field if even a single line of validation or
notification logic is required:
private string _name;
public string Name
{
get => _name;
set => _name = value ?? throw new ArgumentNullException(nameof(value));
}The field-backed property feature resolves this dilemma by
introducing the contextual keyword field, which grants
direct access to the compiler-synthesized backing field inside property
accessors:
public string Name
{
get => field;
set => field = value ?? throw new ArgumentNullException(nameof(value));
}This syntax is useful for domain model validation, whitespace
trimming, and triggering INotifyPropertyChanged events
without polluting the enclosing type with explicit private field
declarations.
Timeline and Breaking Changes
While the Lock object feature fully shipped with C# 13
and .NET 9, field-backed properties encountered migration challenges
during development. Introducing field as a contextual
keyword posed a breaking change for existing codebases that already
contained members, local variables, or parameters named
field.
To ensure safety and resolve naming ambiguities (such as allowing
@field to reference an existing identifier versus the
backing field), Microsoft made field-backed properties an opt-in preview
feature in C# 13. Full adoption, finalized disambiguation rules, and
general availability are targeted for C# 14.