自动属性用{ get; set; }语法,适合无逻辑的简单读写;需校验、事件、懒加载时用完整属性;访问修饰符可单独设置;注意序列化和绑定对getter的要求。

自动属性怎么写,什么时候该用
自动属性是 C# 最常用、最省事的属性写法,编译器会帮你生成私有后备字段和默认的 get/set 实现。它适合“只做简单读写、不加逻辑、不干预赋值过程”的场景。
常见错误:以为自动属性能直接初始化非空引用类型(比如 List<string></string>),结果运行时报 NullReferenceException。
-
public string Name { get; set; }—— 最简形式,背后有编译器生成的隐藏字段 -
public int Age { get; private set; } = 18;—— 只读属性(外部不可改),支持内联初始化 -
public List<string> Tags { get; set; } = new List<string>();</string></string>—— 必须显式初始化,否则实例化后Tags是null
完整属性(手动实现 get/set)解决什么问题
当你需要在取值或赋值时执行逻辑(比如校验、触发事件、懒加载、转换数据格式),就必须写完整属性。这时候你完全控制字段访问流程,但也要自己管理后备字段。
容易踩的坑:忘记在 set 中给后备字段赋值,或者误用属性名本身导致无限递归。
- 必须声明一个私有字段(如
private string _name;),get和set都操作它 -
set中别写Name = value;,这会调用自身属性,栈溢出 - 校验逻辑建议放在
set里,比如:if (value == null) throw new ArgumentNullException(nameof(value)); - 懒加载常见写法:
private List<int> _items; public List<int> Items => _items ??= new List<int>();</int></int></int>
get/set 访问修饰符不同会怎样
可以单独给 get 或 set 设访问级别,这是控制封装粒度的关键手段。不是语法糖,是真实影响调用方能否读/写。
典型误用:把 set 设为 protected 却忘了子类可能需要访问基类字段,结果子类无法修改——其实应该用 protected set 而非 private set。
-
public string Id { get; internal set; }—— 同程序集内可改,跨程序集只能读 -
public DateTime CreatedAt { get; private set; } = DateTime.Now;—— 构造后不可变,但本类内部仍可改 -
public bool IsReady { get; protected set; }—— 子类可设,外部不行;注意:protected对属性生效,不是对字段
性能和兼容性要注意的点
自动属性和完整属性在 IL 层级生成的代码不同,但现代 JIT 优化下,纯读写场景性能差异几乎为零。真正影响性能的是你在 get/set 里写的逻辑,不是属性本身。
容易被忽略的地方:序列化(如 JSON.NET、System.Text.Json)默认只处理 public 属性,且要求有 public getter;如果只有 private setter,得配 [JsonInclude] 或配置选项。
- 自动属性在 .NET Framework 2.0+ 支持,完整属性无版本限制
- 反序列化时,如果属性没有 public getter,多数序列化器会跳过它
- WPF 绑定依赖
INotifyPropertyChanged,这时必须用完整属性 + 手动触发事件,自动属性做不到 - EF Core 映射实体时,private setter 是允许的,但字段不能是
readonly
属性看着简单,但 get/set 的访问修饰符、初始化时机、序列化行为、绑定上下文,这几处一叠加,很容易漏掉某条路径的约束。写之前先想清楚:这个值谁要读、谁要改、改的时候要不要拦一下、改完要不要通知别人。


















