封装 #
一、封装概述 #
封装是面向对象编程的核心特性之一,它通过隐藏内部实现细节,只暴露必要的接口来保护数据。
1.1 封装的好处 #
- 数据保护
- 隐藏实现细节
- 提供统一接口
- 降低耦合度
二、访问修饰符 #
2.1 访问级别 #
| 修饰符 | 同一类 | 子类 | 同程序集 | 外部程序集 |
|---|---|---|---|---|
| public | ✓ | ✓ | ✓ | ✓ |
| protected internal | ✓ | ✓ | ✓ | - |
| internal | ✓ | - | ✓ | - |
| protected | ✓ | ✓ | - | - |
| private protected | ✓ | ✓(同程序集) | - | - |
| private | ✓ | - | - | - |
2.2 使用示例 #
csharp
public class Person
{
public string Name { get; set; }
private int _age;
protected string _id;
internal string _code;
protected internal string _tag;
private protected string _internalId;
public int Age
{
get => _age;
set
{
if (value >= 0 && value <= 150)
_age = value;
}
}
}
2.3 默认访问级别 #
csharp
class DefaultClass
{
int defaultField;
void DefaultMethod() { }
}
三、属性 #
3.1 基本属性 #
csharp
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
3.2 自动属性 #
csharp
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
3.3 只读属性 #
csharp
public class Person
{
public string Name { get; }
public DateTime CreatedAt { get; } = DateTime.Now;
public Person(string name)
{
Name = name;
}
}
3.4 私有set #
csharp
public class Person
{
public string Name { get; private set; }
public void ChangeName(string newName)
{
if (!string.IsNullOrEmpty(newName))
Name = newName;
}
}
3.5 计算属性 #
csharp
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
public double Area => Width * Height;
public double Perimeter => 2 * (Width + Height);
}
3.6 表达式体属性 #
csharp
public class Person
{
private string _firstName;
private string _lastName;
public string FullName => $"{_firstName} {_lastName}";
public string Name
{
get => _firstName;
set => _firstName = value;
}
}
3.7 属性验证 #
csharp
public class Person
{
private int _age;
public int Age
{
get => _age;
set
{
if (value < 0 || value > 150)
throw new ArgumentOutOfRangeException(nameof(value));
_age = value;
}
}
private string _email;
public string Email
{
get => _email;
set
{
if (value != null && !value.Contains("@"))
throw new FormatException("邮箱格式不正确");
_email = value;
}
}
}
3.8 init属性(C# 9+) #
csharp
public class Person
{
public string Name { get; init; }
public int Age { get; init; }
}
var person = new Person { Name = "张三", Age = 25 };
3.9 required属性(C# 11+) #
csharp
public class Person
{
public required string Name { get; set; }
public required string Email { get; set; }
public int Age { get; set; }
}
var person = new Person { Name = "张三", Email = "test@example.com" };
四、索引器 #
4.1 基本语法 #
csharp
public class NumberList
{
private int[] _numbers = new int[10];
public int this[int index]
{
get => _numbers[index];
set => _numbers[index] = value;
}
}
var list = new NumberList();
list[0] = 100;
int value = list[0];
4.2 字符串索引器 #
csharp
public class StringDictionary
{
private Dictionary<string, string> _data = new();
public string this[string key]
{
get => _data.TryGetValue(key, out var value) ? value : null;
set => _data[key] = value;
}
}
var dict = new StringDictionary();
dict["name"] = "张三";
string name = dict["name"];
4.3 多参数索引器 #
csharp
public class Matrix
{
private int[,] _data;
public Matrix(int rows, int cols)
{
_data = new int[rows, cols];
}
public int this[int row, int col]
{
get => _data[row, col];
set => _data[row, col] = value;
}
}
var matrix = new Matrix(3, 3);
matrix[0, 0] = 1;
int value = matrix[0, 0];
4.4 只读索引器 #
csharp
public class WeekDays
{
private string[] _days = { "周一", "周二", "周三", "周四", "周五", "周六", "周日" };
public string this[int index] => _days[index];
}
五、封装最佳实践 #
5.1 使用属性代替公共字段 #
csharp
public class Person
{
public string Name { get; set; }
public string Name;
}
5.2 验证输入 #
csharp
public class BankAccount
{
private decimal _balance;
public decimal Balance
{
get => _balance;
private set
{
if (value < 0)
throw new InvalidOperationException("余额不能为负数");
_balance = value;
}
}
public void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("存款金额必须大于0");
Balance += amount;
}
}
5.3 使用私有字段存储数据 #
csharp
public class Person
{
private string _name;
public string Name
{
get => _name ?? "未知";
set => _name = string.IsNullOrWhiteSpace(value) ? "未知" : value.Trim();
}
}
5.4 不可变对象 #
csharp
public class ImmutablePerson
{
public string Name { get; }
public int Age { get; }
public ImmutablePerson(string name, int age)
{
Name = name;
Age = age;
}
public ImmutablePerson WithAge(int newAge) => new(Name, newAge);
}
六、实战示例 #
6.1 温度类 #
csharp
public class Temperature
{
private double _celsius;
public double Celsius
{
get => _celsius;
set
{
if (value < -273.15)
throw new ArgumentOutOfRangeException(nameof(value), "温度不能低于绝对零度");
_celsius = value;
}
}
public double Fahrenheit
{
get => Celsius * 9 / 5 + 32;
set => Celsius = (value - 32) * 5 / 9;
}
public double Kelvin
{
get => Celsius + 273.15;
set => Celsius = value - 273.15;
}
public Temperature(double celsius)
{
Celsius = celsius;
}
public static Temperature FromFahrenheit(double fahrenheit)
{
return new Temperature((fahrenheit - 32) * 5 / 9);
}
}
6.2 购物车类 #
csharp
public class ShoppingCart
{
private readonly List<CartItem> _items = new();
public IReadOnlyList<CartItem> Items => _items.AsReadOnly();
public decimal Total => _items.Sum(i => i.Price * i.Quantity);
public int ItemCount => _items.Sum(i => i.Quantity);
public CartItem this[int productId]
{
get => _items.FirstOrDefault(i => i.ProductId == productId);
}
public void AddItem(int productId, string name, decimal price, int quantity = 1)
{
var existingItem = _items.FirstOrDefault(i => i.ProductId == productId);
if (existingItem != null)
{
existingItem.Quantity += quantity;
}
else
{
_items.Add(new CartItem
{
ProductId = productId,
Name = name,
Price = price,
Quantity = quantity
});
}
}
public void RemoveItem(int productId)
{
_items.RemoveAll(i => i.ProductId == productId);
}
public void Clear()
{
_items.Clear();
}
}
public class CartItem
{
public int ProductId { get; init; }
public string Name { get; init; }
public decimal Price { get; init; }
public int Quantity { get; set; }
}
七、总结 #
封装要点:
| 要点 | 说明 |
|---|---|
| 访问修饰符 | 控制访问级别 |
| 属性 | 封装字段 |
| 索引器 | 数组式访问 |
| 验证 | 保护数据完整性 |
下一步,让我们学习继承!
最后更新:2026-03-26