====== 第五章 类与对象 ======
===== 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)的特性
掌握这些知识是面向对象编程的基础。