BRO1144: Escape identifiers that C# 14 reads as keywords¶
C# 14 reads field, extension and partial as keywords in places where they used to be plain names. Code that used
such a name there changes meaning or stops compiling when the project moves to C# 14 (.NET 10's default). BRO1144
writes @ before the name in exactly those places; @field means the same in every C# version. Not a StyleCop rule
(Sonar S8367, S8368 and S8380 report these without a fix; the compiler's CS9258 warning has no fix either).
Example¶
Before¶
public class Counter
{
private int field;
public int Value
{
get => field;
set => field = value;
}
public int Read() => this.field;
}
After¶
public class Counter
{
private int field;
public int Value
{
get => @field;
set => @field = value;
}
public int Read() => this.field;
}
Why¶
In C# 14, field inside a property accessor is the property's own backing field. get => field; above stops reading
the class's field field and reads a new, hidden one instead: the code still compiles (warning CS9258), but Value
and Read() no longer see the same storage. With @field it keeps its meaning in every language version, so a
multi-targeted project (net48;net10.0, where each target framework compiles with its own C# version) behaves the same
everywhere.
What is reported¶
These are the cases in Roslyn's list of C# 14 breaking changes, each checked with the C# 14 compiler:
| Before | After | In C# 14 without @ |
|---|---|---|
field in a property's accessor or expression body (also in a lambda or local function there) that names a member, local, parameter or range variable |
@field |
the backing field (CS9258), or error CS9272/CS9273 for a local or parameter declared there |
a type, delegate, type parameter or using alias named extension |
@extension |
error CS9306 |
a member of a type whose declaration starts with the type name extension (extension M(), extension[] items;, a constructor of a type named extension) |
@extension M() |
read as an extension block: syntax errors |
a method or local function returning a type named partial (partial F()) |
@partial F() |
read as a partial member: errors |
In code that already compiles as C# 14, a field keyword is reported only when a member, local or parameter named
field of the property's type is in scope (the CS9258 case). Next to a member of another type (a string property in
a class with an int field named field) the keyword can only mean the backing field and stays.
Not reported¶
this.field,x.field,x?.field, named arguments (M(field: 1)) and anonymous object members (new { field = 1 }): they stay names in C# 14.fieldin an indexer or event accessor, or anywhere outside a property: not a keyword there.extensionused as a type anywhere else (a parameter, a local,new extension()), andpartialas the type of a field, property or parameter, or in an array return type (partial[] F()): C# 14 compiles these unchanged.scopedas a type name of a lambda parameter ((scoped s) => ..., Sonar S8381): a narrower case, not covered.- Code with syntax errors around the name.
Renaming rules and C# 14¶
When a member named field is also renamed (BRO1303, BRO1306, ...), the rename takes the
field keywords that mean the member along with it (get => field; becomes get => _field;), so the escape and the
rename give the same result in one dotnet format run, in either order (checked with a C# 14 project and the SDK 10
compiler, 2026-10-06).
Compared with StyleCop¶
StyleCop has no such rule. stylebro-migrate turns it off (see
Rules beyond StyleCop).