Exploring the New 'field' Keyword in C# 14 with .NET 10 Preview 2
As someone who’s always excited about the latest developments in the .NET ecosystem, I recently got my hands on .NET 10 Preview 2, and with it, C# 14.
Among the several new features introduced, one particularly elegant addition stood out to me—the field
keyword for property accessors.
It’s a small addition on the surface, but it has significant implications for cleaner, more expressive code.
In this post, I’ll walk through what the field
keyword does, how it simplifies property declarations, and some edge cases to be aware of.
The Problem with Traditional Property Backing Fields
Before C# 14, if you wanted to perform logic inside a property accessor—like validating input—you had to manually declare a backing field. Here’s a typical example where we ensure a string property can’t be set to null
:
private string _message;
public string Message
{
get => _message;
set => _message = value ?? throw new ArgumentNullException(nameof(value));
}
This works fine, but it’s verbose. You end up duplicating property and field names, and it breaks the neatness of auto-properties.
The Solution: Enter the field
Keyword
C# 14 introduces a new contextual keyword called field
, which allows us to directly access the compiler-generated backing field of an auto-property inside the accessor logic.
Here’s how the previous code looks using the new field
keyword:
public string Message
{
get;
set => field = value ?? throw new ArgumentNullException(nameof(value));
}
✨ Much cleaner, right?
You get the benefit of auto-properties and the ability to add logic, all without manually declaring a backing field.
How It Works
field
is a contextual keyword, meaning it only has special meaning inside property accessors.- It references the compiler-generated backing field that underlies an auto-property.
- You can use
field
inget
orset
, or both, depending on your logic needs.
Example with both:
public int Age
{
get => field;
set => field = value > 0 ? value : throw new ArgumentOutOfRangeException(nameof(value));
}
When Should You Use field
?
Use the field
keyword when:
- You want to add simple logic (validation, transformation) in an accessor.
- You don’t want to manually manage a backing field.
- You want your property declarations to remain compact and readable.
This change encourages better encapsulation and makes it easier to refactor.
Disambiguation: What if You Already Have a Variable Named field
?
Since field
is a contextual keyword, it only has special meaning inside property accessors.
But what happens when you already have a local or class-level variable named field
, it can create ambiguity.
Let’s explore that with a practical example:
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("C# 14 Field Keyword");
}
static int field = 3;
internal class Employee
{
public string Name
{
get;
set
{
field = value.Length > @field ? value : throw new ArgumentException("Name is too short.");
}
}
}
}
If you already have a variable named field
(like the static variable in the Program
class), and you also want to use the new contextual field
keyword within a property, you must escape your variable name using @field
.
This tells the compiler:
“Hey, I’m referring to the user-defined variable, not the backing field.”
🧠 Code Explanation:
static int field = 3;
This defines a static variable namedfield
in the outerProgram
class.Inside the nested
Employee
class, theName
property uses:field = value.Length > @field ? value : throw new ArgumentException(...);
- On the left-hand side,
field =
refers to the compiler-generated backing field for theName
property. This is a new feature introduced in C# 14. - On the right-hand side,
@field
refers to our static variable from the outerProgram
class.
- On the left-hand side,
So the logic here checks:
- If the incoming
value
(i.e., the name being set) is longer than 3 characters (@field
= 3), - Then it gets assigned to the backing field via the new
field
keyword, - Otherwise, it throws an exception.
If you try to assign a name with more than 3 characters — say "John"
— it will be accepted. Anything shorter, like "Al"
, will raise an error:
ArgumentException: Name is too short.
Let’s take another example — this time, we have a class-level field named field
.
public class Person
{
private int field = 18;
public int Age
{
get;
set => field = value > this.field ? value : throw new ArgumentException("Age must be higher than the existing field.");
}
}
🧠 Code Explanation:
this.field
refers to the class-level variable holding the value18
.field =
on the left side refers to the auto-generated backing field of theAge
property.
So this line of code means:
👉 Assign the new value to the property only if it’s greater than the existing field
variable.
By using this.field
, you’re making it crystal clear that you’re talking about the class-level variable — which avoids confusion with the compiler’s contextual field
.
Or you can use @field
also.
🧠 Tip: When dealing with properties using the field
keyword, it’s best to avoid naming other variables field
.
If necessary, you can use @field
to refer local variable and this.field
or @field
to reference class level fields.
Let field
(without @
) refer to the auto-property backing field.
Limitations and Notes
- This feature is only available starting with C# 14, which you can try by installing .NET 10 Preview 2 and setting your
LangVersion
topreview
. - The compiler only synthesizes a backing field if both accessors (
get
/set
) do not contain logic that prevents auto-property generation (e.g., referencing external members). - Not suitable for complex getter logic or if you want custom fields unrelated to properties.
Getting Started with C# 14 and .NET 10 Preview 2
To test this out:
- Install .NET 10 Preview 2 SDK.
- Create a new project:
dotnet new console -n CSharp14FieldDemo cd CSharp14FieldDemo
- Edit your
.csproj
to use the preview language features:<PropertyGroup> <LangVersion>preview</LangVersion> </PropertyGroup>
- Write your code and explore!
Final Thoughts
The introduction of the field
keyword may seem like a minor syntactic sugar at first glance, but it reinforces C#’s philosophy of clear, concise, and expressive code. It strikes a nice balance between automation and control, giving you just enough power without the boilerplate.
If you’re already testing out .NET 10, I highly recommend trying this feature—it’s a subtle but satisfying upgrade.
Happy coding! 👨💻🚀