C# - 封装
C# - 封装
Section titled “C# - 封装”封装是面向对象编程(OOP)的四个基本原则之一。它指的是将数据(字段或属性)与操作该数据的方法(或函数)捆绑到一个单一单元或“类”中。更重要的是,它涉及限制对对象内部状态的直接访问。这也被称为信息隐藏。
通过隐藏实现细节,封装有助于管理复杂性,提高健壮性(通过阻止外部代码将对象置于无效状态),并改善可维护性。
使用属性实现封装
Section titled “使用属性实现封装”在 C# 中,封装主要通过结合**属性(properties)和访问修饰符(access modifiers)**来实现。我们不直接公开数据字段,而是通过属性公开它们,这些属性看起来像字段,但在 get 和 set 访问器中包含逻辑。
问题:公共字段
Section titled “问题:公共字段”公开字段被认为是不良实践,因为您会失去对数据的所有控制。任何外部代码都可以将字段更改为任意值,从而可能破坏对象的内部规则(不变量)。
public class Employee{ // 不良实践:公共字段可能被设置为无效值。 public double salary;}
var emp = new Employee();emp.salary = -5000; // 失控的无效状态!解决方案:带支持字段的属性
Section titled “解决方案:带支持字段的属性”带有支持字段的属性允许您添加验证逻辑。数据存储在 private(私有)字段中,并通过 public(公共)属性控制访问。
public class Employee{ // 1. 私有支持字段,用于存储数据 private double _salary;
// 2. 公共属性,用于控制访问 public double Salary { get { return _salary; } // 'get' 访问器返回私有字段的值 set { // 'set' 访问器验证传入的 'value' if (value < 0) { throw new ArgumentException("Salary cannot be negative."); } _salary = value; } }}
var emp = new Employee();emp.Salary = 50000; // OKConsole.WriteLine($"Employee Salary: {emp.Salary}");
try{ emp.Salary = -100; // 抛出 ArgumentException 异常}catch (Exception ex){ Console.WriteLine(ex.Message);}当上述代码被编译和执行时,会产生以下结果:
Employee Salary: 50000Salary cannot be negative.现代 C# 简化:自动实现的属性
Section titled “现代 C# 简化:自动实现的属性”如果您不需要自定义验证逻辑,C# 提供了一种更简洁的语法,称为自动实现的属性(auto-implemented properties)。编译器会自动为您生成私有支持字段。
public class Car{ // 编译器会创建一个隐藏的私有支持字段。 public string Model { get; set; } public int Year { get; set; }}
var myCar = new Car { Model = "Tesla Model 3", Year = 2023 };Console.WriteLine($"My car: {myCar.Year} {myCar.Model}");使用 init 创建不可变对象
Section titled “使用 init 创建不可变对象”要创建不可变(unchangeable)对象,您可以使用 init-only setter(C# 9+ 中可用)。这确保了属性只能在对象初始化期间设置。
public class Transaction{ public Guid TransactionId { get; init; } public decimal Amount { get; init; } public DateTime Timestamp { get; init; }}
var tx = new Transaction{ TransactionId = Guid.NewGuid(), Amount = 19.99m, Timestamp = DateTime.UtcNow};
// 下面这行代码会导致编译时错误:// tx.Amount = 25.00m; // 错误:Init-only 属性只能在初始化器中赋值。访问修饰符定义了类及其成员的可见性。它们是强制执行封装的核心机制。
public:成员可从任何地方访问。无限制。private:成员仅在同一类内部可访问。这是类成员的默认访问级别,提供了最高级别的封装。protected:成员可在同一类内部以及派生(子)类中访问。internal:成员仅在同一程序集(.dll 或 .exe)内部可访问。这是类的默认访问级别。protected internal:protected或internal的组合。成员可由派生类或同一程序集中的任何类访问。private protected:private和protected的组合。成员仅可由在同一程序集中的派生类访问。