在C#中,类的属性(Property) 是一种特殊成员,它提供了对私有字段的安全访问机制,本质上是通过方法(getter/setter)来封装字段的访问。属性是面向对象编程中封装原则的核心实现之一。
属性的核心作用:
- 控制访问:验证数据有效性
- 数据绑定:支持UI框架(如WPF/WinForms)的绑定机制
- 计算属性:动态返回值
- 接口实现:满足接口契约
基本语法结构:
private string _name; // 私有字段(backing field)
public string Name // 公共属性
{
get { return _name; } // 读取访问器
set { _name = value; } // 写入访问器(value是关键字)
}
属性的高级用法:
1. 自动实现属性(最常用)
public int Age { get; set; } // 编译器自动生成隐藏字段
2. 只读属性
public Guid Id { get; } = Guid.NewGuid(); // 只能在构造函数中赋值
3. 访问权限控制
public string Password { get; private set; } // 外部只读,内部可修改
4. 带验证的setter
private int _score;
public int Score
{
get => _score;
set => _score = (value >= 0 && value <= 100) ? value
: throw new ArgumentException("无效分数");
}
5. 计算属性
public string FullName => $"{FirstName} {LastName}"; // 无setter
6. 初始化器(C# 9+)
public Person()
{
Address = new Address(); // 避免null
}
public Address Address { get; init; } // 只能在对象初始化时赋值
属性 vs 字段:
| 特性 | 字段(Field) | 属性(Property) |
|---|---|---|
| 数据存储 | 直接存储数据 | 通过方法间接访问字段 |
| 验证逻辑 | 无法添加 | 可在setter中添加 |
| 数据绑定支持 | 不支持(WPF等) | 完全支持 |
| 接口实现 | 不能用于接口 | 可实现接口属性 |
| 默认值初始化 | 可直接赋值 | 需通过构造函数/初始化器 |
| 性能 | 稍快(直接内存访问) | 稍慢(方法调用开销) |
💡 最佳实践:
- 永远将字段设为
private- 通过属性暴露对外访问
- 简单场景用自动属性
- 需要验证/计算时用完整属性
特殊属性类型:
-
索引器(类似数组访问的属性):
public string this[int index] { get => _items[index]; set => _items[index] = value; } -
抽象属性(在抽象类中):
public abstract class Shape { public abstract double Area { get; } // 派生类必须实现 } -
接口属性:
public interface IUser { string Email { get; set; } // 实现类必须提供 }
使用场景示例:
public class BankAccount
{
private decimal _balance;
// 带验证的属性
public decimal Balance
{
get => _balance;
private set => _balance = Math.Max(value, 0); // 余额不能为负
}
// 自动实现的只读属性
public string AccountNumber { get; }
// 计算属性
public bool IsOverdrawn => Balance < 0;
public BankAccount(string accNumber)
=> AccountNumber = accNumber;
public void Deposit(decimal amount)
=> Balance += amount;
public void Withdraw(decimal amount)
=> Balance -= amount;
}