====== 第五章 类与对象 ====== ===== 5.1 面向对象基础 ===== === 什么是面向对象 === 面向对象编程(OOP)是一种编程范式,以"对象"为核心,将数据和行为封装在一起。C#是一种完全面向对象的语言。 === 面向对象的三大特性 === | 特性 | 说明 | 作用 | |------|------|------| | 封装 | 隐藏内部实现细节 | 提高安全性,简化使用 | | 继承 | 子类继承父类特性 | 代码复用,建立层次关系 | | 多态 | 同一操作作用于不同对象产生不同行为 | 提高灵活性,便于扩展 | ===== 5.2 类的定义 ===== === 基本类结构 === // 定义类 public class Person { // 字段 private string name; private int age; // 属性 public string Name { get { return name; } set { name = value; } } public int Age { get { return age; } set { if (value >= 0 && value <= 150) age = value; else throw new ArgumentException("年龄必须在0-150之间"); } } // 方法 public void Introduce() { Console.WriteLine($"我叫{Name},今年{Age}岁"); } } // 使用类 Person person = new Person(); person.Name = "张三"; person.Age = 25; person.Introduce(); === 自动属性(C# 3.0+) === public class Student { // 自动实现的属性 public string Name { get; set; } public int Age { get; set; } // 只读属性(C# 6+) public string Id { get; } = Guid.NewGuid().ToString(); // 只写属性(较少使用) public string Password { private get; set; } // 带初始化的自动属性(C# 6+) public DateTime EnrollmentDate { get; set; } = DateTime.Now; } ===== 5.3 构造函数 ===== === 实例构造函数 === public class Car { public string Brand { get; set; } public string Model { get; set; } public int Year { get; set; } // 默认构造函数 public Car() { Brand = "Unknown"; Year = DateTime.Now.Year; } // 带参数的构造函数 public Car(string brand, string model, int year) { Brand = brand; Model = model; Year = year; } // 构造函数重载 public Car(string brand, string model) : this(brand, model, DateTime.Now.Year) { } } // 使用 Car car1 = new Car(); Car car2 = new Car("Toyota", "Corolla", 2024); Car car3 = new Car("Honda", "Civic"); === 静态构造函数 === public class Configuration { public static string AppName { get; private set; } public static string Version { get; private set; } // 静态构造函数,在类首次使用时执行 static Configuration() { AppName = "MyApplication"; Version = "1.0.0"; Console.WriteLine("静态构造函数执行"); } } === 主构造函数(C# 12+) === // 简洁的构造函数语法 public class Point(int x, int y) { public int X { get; } = x; public int Y { get; } = y; public double DistanceFromOrigin() => Math.Sqrt(X * X + Y * Y); } // 使用 var point = new Point(3, 4); Console.WriteLine(point.DistanceFromOrigin()); // 5 ===== 5.4 字段与属性详解 ===== === 字段 === public class BankAccount { // 实例字段 private decimal balance; private string accountNumber; // 静态字段(所有实例共享) private static decimal interestRate = 0.03m; private static int accountCount = 0; // 只读字段(只能在声明时或构造函数中赋值) private readonly DateTime createdDate; // 常量字段(编译时常量) public const string BankName = "中国工商银行"; } === 属性详解 === public class Employee { private decimal salary; // 完整属性定义 public decimal Salary { get { return salary; } set { if (value < 0) throw new ArgumentException("工资不能为负数"); salary = value; } } // 计算属性 public decimal AnnualSalary => Salary * 12; // 表达式属性(C# 6+) public string Info => $"{Name} - {Department}"; // init-only属性(C# 9+) public string Id { get; init; } public string Name { get; set; } public string Department { get; set; } } // 使用init-only属性 var emp = new Employee { Id = "E001", // 只能在初始化时设置 Name = "张三", Department = "技术部" }; // emp.Id = "E002"; // 错误!无法修改 ===== 5.5 方法详解 ===== === 实例方法 === public class Rectangle { public double Width { get; set; } public double Height { get; set; } // 实例方法 public double CalculateArea() { return Width * Height; } public double CalculatePerimeter() { return 2 * (Width + Height); } } === 静态方法 === public static class MathUtils { // 静态方法,不需要实例 public static int Add(int a, int b) => a + b; public static double CircleArea(double radius) => Math.PI * radius * radius; } // 使用 int sum = MathUtils.Add(5, 3); double area = MathUtils.CircleArea(5); ===== 5.6 this关键字 ===== === 引用当前实例 === public class Person { private string name; private int age; public Person(string name, int age) { // 使用this区分字段和参数 this.name = name; this.age = age; } public void PrintInfo() { Console.WriteLine($"Name: {this.name}"); } } === 构造函数链式调用 === public class Product { public string Name { get; set; } public decimal Price { get; set; } public string Category { get; set; } public Product(string name, decimal price) : this(name, price, "未分类") { } public Product(string name, decimal price, string category) { Name = name; Price = price; Category = category; } } ===== 5.7 对象初始化器 ===== // 传统方式 Person p1 = new Person(); p1.Name = "张三"; p1.Age = 25; // 对象初始化器(C# 3.0+) Person p2 = new Person { Name = "李四", Age = 30 }; // 结合构造函数 Person p3 = new Person("王五", 35) { Email = "wangwu@example.com" }; // 集合初始化器 var people = new List { new Person { Name = "Alice", Age = 25 }, new Person { Name = "Bob", Age = 30 }, new Person { Name = "Charlie", Age = 35 } }; ===== 5.8 部分类(Partial Class) ==== // Person.cs public partial class Person { public string FirstName { get; set; } public string LastName { get; set; } } // Person.Methods.cs public partial class Person { public string GetFullName() => $"{FirstName} {LastName}"; } // 编译后会合并成一个类 var person = new Person(); person.FirstName = "John"; person.LastName = "Doe"; Console.WriteLine(person.GetFullName()); ===== 5.9 记录类型(Record,C# 9+) ===== === 记录的定义 === // 不可变记录 public record Person(string FirstName, string LastName, int Age); // 使用 var person = new Person("John", "Doe", 30); Console.WriteLine(person); // 输出: Person { FirstName = John, LastName = Doe, Age = 30 } // 解构 var (first, last, age) = person; === 记录的特性 === // 值相等性 var p1 = new Person("John", "Doe", 30); var p2 = new Person("John", "Doe", 30); Console.WriteLine(p1 == p2); // true(值相等) Console.WriteLine(ReferenceEquals(p1, p2)); // false(不同引用) // with表达式(创建修改后的副本) var p3 = p1 with { Age = 31 }; Console.WriteLine(p3); // John Doe, Age = 31 // 可变记录 public record MutablePerson { public string Name { get; set; } public int Age { get; set; } } ===== 5.10 实战:银行账户类 ===== public class BankAccount { private static int accountCounter = 1000; public string AccountNumber { get; } public string OwnerName { get; set; } public decimal Balance { get; private set; } public DateTime CreatedDate { get; } public List TransactionHistory { get; } public BankAccount(string ownerName, decimal initialBalance = 0) { AccountNumber = $"ACC{++accountCounter}"; OwnerName = ownerName; Balance = initialBalance; CreatedDate = DateTime.Now; TransactionHistory = new List(); if (initialBalance > 0) { RecordTransaction($"开户存入: {initialBalance:C}"); } } public void Deposit(decimal amount) { if (amount <= 0) throw new ArgumentException("存款金额必须大于0"); Balance += amount; RecordTransaction($"存入: {amount:C}, 余额: {Balance:C}"); } public bool Withdraw(decimal amount) { if (amount <= 0) throw new ArgumentException("取款金额必须大于0"); if (amount > Balance) { RecordTransaction($"取款失败: 余额不足 ({amount:C})"); return false; } Balance -= amount; RecordTransaction($"取出: {amount:C}, 余额: {Balance:C}"); return true; } public bool Transfer(BankAccount target, decimal amount) { if (Withdraw(amount)) { target.Deposit(amount); RecordTransaction($"转账给 {target.OwnerName}: {amount:C}"); return true; } return false; } public void PrintStatement() { Console.WriteLine($"\n===== 账户对账单 ====="); Console.WriteLine($"账户号: {AccountNumber}"); Console.WriteLine($"户主: {OwnerName}"); Console.WriteLine($"当前余额: {Balance:C}"); Console.WriteLine($"开户日期: {CreatedDate:yyyy-MM-dd}"); Console.WriteLine("\n交易记录:"); foreach (var transaction in TransactionHistory) { Console.WriteLine($" {transaction}"); } } private void RecordTransaction(string description) { TransactionHistory.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {description}"); } } ===== 练习题 ===== === 基础练习 === 1. **设计Student类**:包含学号、姓名、年龄、成绩等属性,实现: - 构造函数初始化 - 成绩验证(0-100分) - 计算等级(A:90+, B:80+, C:70+, D:60+, F:<60) - 输出学生信息的方法 2. **图书类设计**:创建Book类,包含: - ISBN(只读) - 书名、作者、出版社、价格 - 出版日期 - 方法:显示图书信息、计算已出版年限 3. **时间类**:创建MyTime类表示时间,包含: - 时、分、秒属性 - 构造函数重载 - 方法:增加秒数、格式化输出、比较两个时间 === 进阶练习 === 4. **购物车系统**:设计ShoppingCart类,包含: - 添加商品(商品名、数量、单价) - 删除商品 - 修改数量 - 计算总价 - 应用折扣 - 生成订单摘要 5. **员工管理系统**:创建Employee类层次结构: - 基类Employee(姓名、ID、基本工资) - 派生类SalariedEmployee(月薪) - 派生类HourlyEmployee(时薪、工时) - 派生类CommissionEmployee(底薪+提成) - 每个类实现自己的CalculateEarnings方法 6. **使用记录类型**:将上述Employee类改写为记录类型,利用其不可变性和值相等的特性。 === 挑战练习 === 7. **银行账户升级版**:在实战示例基础上添加: - 不同类型的账户(储蓄、支票、信用卡) - 利息计算 - 月度对账单生成 - 多币种支持 8. **面向对象的图形库**:设计图形类层次: - 抽象基类Shape(颜色、位置) - 派生类:Circle、Rectangle、Triangle - 每个类实现CalculateArea和CalculatePerimeter - 实现绘制方法(控制台输出图形信息) - 创建Shape列表,计算总面积和总周长 ===== 本章小结 ===== 本章学习了C#类和对象的核心概念: - 类的定义和成员 - 字段、属性的区别和使用 - 各种类型的构造函数 - 实例方法和静态方法 - this关键字的用法 - 对象初始化器 - 部分类的概念 - 记录类型(Record)的特性 掌握这些知识是面向对象编程的基础。