用户工具

站点工具


csharp:第五章类与对象

第五章 类与对象

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<Person>
{
    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<string> TransactionHistory { get; }
 
    public BankAccount(string ownerName, decimal initialBalance = 0)
    {
        AccountNumber = $"ACC{++accountCounter}";
        OwnerName = ownerName;
        Balance = initialBalance;
        CreatedDate = DateTime.Now;
        TransactionHistory = new List<string>();
 
        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类:包含学号、姓名、年龄、成绩等属性,实现:

  1. 构造函数初始化
  2. 成绩验证(0-100分)
  3. 计算等级(A:90+, B:80+, C:70+, D:60+, F:<60)
  4. 输出学生信息的方法

2. 图书类设计:创建Book类,包含:

  1. ISBN(只读)
  2. 书名、作者、出版社、价格
  3. 出版日期
  4. 方法:显示图书信息、计算已出版年限

3. 时间类:创建MyTime类表示时间,包含:

  1. 时、分、秒属性
  2. 构造函数重载
  3. 方法:增加秒数、格式化输出、比较两个时间

进阶练习

4. 购物车系统:设计ShoppingCart类,包含:

  1. 添加商品(商品名、数量、单价)
  2. 删除商品
  3. 修改数量
  4. 计算总价
  5. 应用折扣
  6. 生成订单摘要

5. 员工管理系统:创建Employee类层次结构:

  1. 基类Employee(姓名、ID、基本工资)
  2. 派生类SalariedEmployee(月薪)
  3. 派生类HourlyEmployee(时薪、工时)
  4. 派生类CommissionEmployee(底薪+提成)
  5. 每个类实现自己的CalculateEarnings方法

6. 使用记录类型:将上述Employee类改写为记录类型,利用其不可变性和值相等的特性。

挑战练习

7. 银行账户升级版:在实战示例基础上添加:

  1. 不同类型的账户(储蓄、支票、信用卡)
  2. 利息计算
  3. 月度对账单生成
  4. 多币种支持

8. 面向对象的图形库:设计图形类层次:

  1. 抽象基类Shape(颜色、位置)
  2. 派生类:Circle、Rectangle、Triangle
  3. 每个类实现CalculateArea和CalculatePerimeter
  4. 实现绘制方法(控制台输出图形信息)
  5. 创建Shape列表,计算总面积和总周长

本章小结

本章学习了C#类和对象的核心概念:

  1. 类的定义和成员
  2. 字段、属性的区别和使用
  3. 各种类型的构造函数
  4. 实例方法和静态方法
  5. this关键字的用法
  6. 对象初始化器
  7. 部分类的概念
  8. 记录类型(Record)的特性

掌握这些知识是面向对象编程的基础。

csharp/第五章类与对象.txt · 最后更改: 127.0.0.1