自动属性允许在不显式定义 backing field 的情况下声明属性。编译器在后台生成一个隐藏的私有字段。
// 基本自动属性示例
public class Person
{
public string Name { get; set; } // 自动生成支持字段
public int Age { get; set; }
}
上述代码中,
Name 和
Age 属性由编译器自动实现,等价于手动编写 getter 和 setter 访问器及私有字段。
自动属性的演进阶段
C# 在不同版本中持续改进自动属性功能:
C# 3.0:引入自动属性,支持简单 get/set
C# 6.0:支持自动属性初始化器
C# 7.0 及以上:支持表达式体成员和只读自动属性的改进
例如,使用 C# 6.0 的属性初始化器:
// C# 6.0 新增:自动属性初始化器
public class Settings
{
public string Theme { get; set; } = "Dark";
public bool NotificationsEnabled { get; set; } = true;
}
该特性允许在声明时直接赋初值,无需构造函数介入。
只读自动属性
从 C# 6.0 开始,支持只读自动属性,通过构造函数设置其值:
public class Product
{
public string Id { get; } // 只读自动属性
public string Name { get; }
public Product(string id, string name)
{
Id = id;
Name = name;
}
}
public class Person
{
public string Name { get; set; }
}
// 使用反射访问Name属性背后的字段
var field = typeof(Person).GetField("<Name>k__BackingField",
BindingFlags.NonPublic | BindingFlags.Instance);
var instance = new Person { Name = "Alice" };
var value = field?.GetValue(instance); // 输出: Alice
public class Order
{
public Guid Id { get; private set; }
public decimal TotalAmount { get; private set; }
}
上述代码利用自动属性减少样板代码,
private set 确保属性只能在类内部修改,增强封装性。
引入支持字段处理业务约束
当属性需验证或触发副作用时,应使用支持字段:
private decimal _totalAmount;
public decimal TotalAmount
{
get => _totalAmount;
private set => _totalAmount = value >= 0 ? value : throw new ArgumentException("金额不能为负");
}
public class Person
{
public string Name { get; }
public int Age { get; }
public Person(string name, int age)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name cannot be null or empty.");
if (age < 0)
throw new ArgumentException("Age cannot be negative.");
Name = name;
Age = age;
}
}
上述代码中,
Name 和
Age 为只读自动属性,其值在构造函数中完成初始化。通过私有化设值操作,实现了不可变对象的设计原则,增强了数据安全性。
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public string Name { get; set; } // 自动属性,无需额外逻辑
}