封装 #

一、封装概述 #

封装是面向对象编程的核心特性之一,它通过隐藏内部实现细节,只暴露必要的接口来保护数据。

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