New properties in C# 14 (.NET 10)


First, let me explain what properties are for those who are not familiar with them yet.

A property is something between a field and a method.
It looks like a field, but it behaves more like a method.

Outside the class that contains the property, it looks like a field.
This means that you can use expressions such as car.X += 10;
Inside the class, however, the property's accessors can contain logic when needed.

Example of an older property (C# 13, .NET 9):

private int _x;
public int X
{
    get
    {
        return _x;
    }
    set
    {
        if (value < 0)
        {
            _x = 0;
        }
        else if (value > 800)
        {
            _x = 800;
        }
        else
        {
            _x = value;
        }
    }
}

As you can see in this example above, you can control the logic of the property.
You can make the example above more concise:

private int _x;
public int X
{
    get => _x;
    set => _x = Math.Clamp(value, 0, 800);
}

Note: If value is less than the minimum, Math.Clamp returns the minimum. If it is greater than the maximum, it returns the maximum; otherwise, it returns the value unchanged.

The disadvantage of the older approach is clear.
Inside the class, it is possible to access the backing field _x directly instead of using the property X. In that case, the property's validation logic is bypassed.


The new approach (C# 14, .NET 10):

C# 14 introduces the contextual keyword field. With it, you no longer need to declare an explicit backing field, such as int _x, for the property.

public int X
{
    get;
    set
    {
        if (value < 0)
        {
            field = 0;
        }
        else if (value > 800)
        {
            field = 800;
        }
        else
        {
            field = value;
        }
    }
}

value is the value being assigned to the property.
field refers to the property's compiler-generated backing field.

The concise version looks like this:

public int X
{
    get;
    set => field = Math.Clamp(value, 0, 800);
}

If you do not need any logic in the property accessors, you can use an auto-implemented property.
It looks like this:

public int X { get; set; }   // Same as in C# 13

For more information about what is new in C# 14, see:
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14