返回

C# 14的field关键字怎么使用?属性访问器新写法完整示例

2026-10-03 C# C#14 12 0

C# 14 引入了一个很实用的属性语法:field 关键字。它允许开发者在 get、set 或 init 访问器中直接访问属性对应的编译器生成后备字段,不需要再单独声明 _name、_value 这类私有字段。

这个功能已经随 .NET 10 正式发布。

field关键字是什么?

以前写一个带简单校验的属性,通常需要声明后备字段:

private string _name = string.Empty;

public string Name
{
    get => _name;
    set => _name = value.Trim();
}

C# 14 可以直接写成:

public string Name
{
    get;
    set => field = value.Trim();
}

这里的 field 就代表该属性对应的编译器生成后备字段。get; 保留自动访问器,set 则加入自己的处理逻辑。

这种写法可以减少大量重复代码,同时保留属性访问器的控制能力。

最常见的属性校验

例如用户名不能为 null,可以直接在 set 中处理:

public class User
{
    public string Name
    {
        get;
        set => field = value ?? throw new ArgumentNullException(nameof(value));
    }
}

使用时:

var user = new User
{
    Name = "Tom"
};

Console.WriteLine(user.Name);

如果传入 null,setter 会抛出异常。

相比传统 _name 字段方案,属性本身已经包含了存储和赋值逻辑,代码更加紧凑。

get和set可以混合使用

C# 14 的一个重要变化,是属性可以混合使用自动访问器和带方法体的访问器。

例如:

public int Age
{
    get;
    set
    {
        if (value < 0 || value > 150)
            throw new ArgumentOutOfRangeException(nameof(value));

        field = value;
    }
}

这里 get; 自动读取后备字段,set 负责检查输入范围。

也可以使用表达式主体:

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

这样就不需要额外声明 _age。

使用field实现数据规范化

field 很适合处理字符串:

public string Email
{
    get;
    set => field = value?.Trim().ToLowerInvariant() ?? string.Empty;
}

调用:

user.Email = "  TEST@EXAMPLE.COM  ";

Console.WriteLine(user.Email);

最终保存的值会变成test@example.com。这类场景过去通常需要一个私有字段配合完整的 get、set 访问器,现在可以直接写在属性内部。

field实现延迟初始化

field 也可以用于懒加载:

public DatabaseConnection Connection
{
    get => field ??= CreateConnection();
}

private DatabaseConnection CreateConnection()
{
    return new DatabaseConnection();
}

第一次访问 Connection 时创建对象,后续访问直接返回已经保存的实例。

微软官方文档也将 field ??= 列为 C# 14 中典型的懒初始化用法。

init访问器也可以使用field

如果属性只能在对象初始化阶段赋值,可以配合 init:

public class Product
{
    public string Name
    {
        get;
        init => field = value?.Trim()
            ?? throw new ArgumentNullException(nameof(value));
    }

    public decimal Price
    {
        get;
        init
        {
            if (value < 0)
                throw new ArgumentOutOfRangeException(nameof(value));

            field = value;
        }
    }
}

创建对象:

var product = new Product
{
    Name = "  C# 14 ",
    Price = 99
};

Console.WriteLine(product.Name);

对象初始化完成后,init 属性不能再通过普通赋值修改。

属性通知也能直接操作field

在需要触发属性变化通知的场景中,也可以直接使用 field:

public string Name
{
    get;
    set
    {
        if (field == value)
            return;

        field = value;
        OnPropertyChanged(nameof(Name));
    }
}

完整示例:

public class User : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    public string Name
    {
        get;
        set
        {
            if (field == value)
                return;

            field = value;
            OnPropertyChanged(nameof(Name));
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(
            this,
            new PropertyChangedEventArgs(propertyName));
    }
}

这里没有 _name 字段,属性依然拥有自己的编译器生成存储空间。

field和普通字段有什么区别?

field 不是一个需要自己声明的变量,也不能在类中单独使用:

field = "test"; // 错误

它只在相关属性的访问器上下文中代表该属性的后备字段。

另外,C# 14 中 field 属于上下文关键字。如果项目以前存在名为 field 的变量,在升级到 C# 14 后可能产生歧义。官方建议使用 @field 或 this.field 处理相关标识符冲突。

项目需要什么版本?

field 是 C# 14 的语言功能,正式版本随 .NET 10 发布。如果项目使用 .NET 10 SDK,可以直接使用 C# 14。对于旧项目,除了检查目标框架,还需要确认项目实际使用的 C# 语言版本。

总结

C# 14 的 field 主要解决一个很常见的问题:属性只有一点额外逻辑时,不想为了它专门创建一个私有后备字段。

最常见的写法就是:

public string Name
{
    get;
    set => field = value.Trim();
}

需要校验时可以写 set 方法体,需要懒加载时可以使用 field ??=,需要初始化阶段校验则可以配合 init。对于原本大量使用 _xxx 后备字段的代码,C# 14 的这种属性写法可以明显减少模板代码,同时保持属性本身的可读性。

顶部