get 和 set 是属性的访问器,不是方法也不是字段
在 C# 中,
get和
set只能出现在属性(
property)定义内部,用来控制对底层字段的读写逻辑。它们不是独立可调用的函数,也不能像方法那样传参或被显式调用。
常见误解是把属性当成“带括号的方法”,比如写
obj.Name()—— 这会报错,正确写法是
obj.Name(无括号)。
get语句块必须返回与属性类型一致的值,且不能有参数
set语句块隐含一个名为
value的参数,类型自动匹配属性类型 可以单独省略
get或
set(如只读/只写属性),但至少保留一个
自动属性 vs 手动实现 get/set
多数场景推荐用自动属性(
public string Name { get; set; }),编译器自动生成隐藏字段和默认访问器。只有当你需要校验、触发事件、延迟加载或日志时,才手动展开。
手动实现时,必须显式声明私有字段,并在
get/
set中操作它;否则会无限递归调用自身(比如在
get里直接 return
Name)。
private string _name;
public string Name
{
get { return _name; }
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Name cannot be null or empty");
_name = value.Trim();
}
}set 访问器里的 value 是隐式参数,不能重命名
value是 C# 为
set访问器预定义的关键词,作用域仅限于该
set块内。你不能把它改成
newValue或加
var声明,否则编译失败。 错误写法:
set { string newValue = value; _name = newValue; }(虽然不报错,但 string newValue是冗余声明) 更错误写法:
set (string v) { _name = v; }(C# 不支持给 set加自定义参数) 正确写法就是直接用
value,它类型由属性决定,无需声明
只读属性和 init-only 属性的差异
C# 6 开始支持只读自动属性:
public string Id { get; } = Guid.NewGuid().ToString();,只能在声明时或构造函数中赋值。
C# 9 引入
init访问器,允许在对象初始化器中赋值,之后不可改:
public string Tag { get; init; }。注意 init不是
set的别名,二者互斥;用了
init就不能再有
set。
容易踩坑的是:在构造函数里给
init属性赋值是合法的,但通过反射或
MemberInfo.SetValue强行修改会抛
InvalidOperationException。
