Skip to content

C# 类和对象

本章将详细介绍 C# 面向对象编程的核心概念——类和对象,包括类的定义、对象的创建、构造函数、析构函数等基础知识。

面向对象编程概述

面向对象的基本概念

csharp
// 面向对象编程的四大特性:
// 1. 封装 (Encapsulation) - 隐藏内部实现细节
// 2. 继承 (Inheritance) - 代码重用和扩展
// 3. 多态 (Polymorphism) - 同一接口的不同实现
// 4. 抽象 (Abstraction) - 提取共同特征

// 类是对象的模板或蓝图
public class Person
{
    // 字段 (Fields) - 存储数据
    private string name;
    private int age;
    
    // 属性 (Properties) - 控制数据访问
    public string Name 
    { 
        get { return name; } 
        set { name = value; } 
    }
    
    public int Age 
    { 
        get { return age; } 
        set { age = value >= 0 ? value : 0; } 
    }
    
    // 方法 (Methods) - 定义行为
    public void Introduce()
    {
        Console.WriteLine($"我是 {Name},今年 {Age} 岁。");
    }
}

// 使用类创建对象
static void Main()
{
    // 创建对象实例
    Person person1 = new Person();
    person1.Name = "Alice";
    person1.Age = 25;
    person1.Introduce();
    
    Person person2 = new Person();
    person2.Name = "Bob";
    person2.Age = 30;
    person2.Introduce();
}

类的定义

基本类结构

csharp
// 完整的类定义语法
[访问修饰符] [修饰符] class 类名 [: 基类] [, 接口1, 接口2, ...]
{
    // 字段
    // 属性
    // 构造函数
    // 方法
    // 事件
    // 嵌套类型
}

// 示例:学生类
public class Student
{
    // 常量
    public const int MaxAge = 150;
    
    // 静态字段
    private static int studentCount = 0;
    
    // 实例字段
    private string studentId;
    private string name;
    private int age;
    private List<string> courses;
    
    // 静态属性
    public static int StudentCount 
    { 
        get { return studentCount; } 
    }
    
    // 实例属性
    public string StudentId 
    { 
        get { return studentId; } 
        private set { studentId = value; }  // 私有 setter
    }
    
    public string Name 
    { 
        get { return name; } 
        set 
        { 
            if (!string.IsNullOrWhiteSpace(value))
                name = value; 
        } 
    }
    
    public int Age 
    { 
        get { return age; } 
        set 
        { 
            if (value >= 0 && value <= MaxAge)
                age = value; 
        } 
    }
    
    // 只读属性
    public int CourseCount 
    { 
        get { return courses.Count; } 
    }
    
    // 构造函数
    public Student(string name, int age)
    {
        this.studentId = GenerateStudentId();
        this.Name = name;
        this.Age = age;
        this.courses = new List<string>();
        studentCount++;
    }
    
    // 私有方法
    private string GenerateStudentId()
    {
        return $"STU{DateTime.Now.Year}{(studentCount + 1):D4}";
    }
    
    // 公共方法
    public void AddCourse(string courseName)
    {
        if (!string.IsNullOrWhiteSpace(courseName) && !courses.Contains(courseName))
        {
            courses.Add(courseName);
        }
    }
    
    public void RemoveCourse(string courseName)
    {
        courses.Remove(courseName);
    }
    
    public string[] GetCourses()
    {
        return courses.ToArray();
    }
    
    public void DisplayInfo()
    {
        Console.WriteLine($"学号: {StudentId}");
        Console.WriteLine($"姓名: {Name}");
        Console.WriteLine($"年龄: {Age}");
        Console.WriteLine($"课程数: {CourseCount}");
        if (courses.Count > 0)
        {
            Console.WriteLine($"课程: {string.Join(", ", courses)}");
        }
    }
    
    // 静态方法
    public static void DisplayStatistics()
    {
        Console.WriteLine($"总学生数: {StudentCount}");
    }
}

访问修饰符

csharp
public class AccessModifierDemo
{
    // public - 公共访问,任何地方都可以访问
    public string PublicField = "公共字段";
    
    // private - 私有访问,只能在当前类内部访问
    private string privateField = "私有字段";
    
    // protected - 受保护访问,当前类和派生类可以访问
    protected string protectedField = "受保护字段";
    
    // internal - 内部访问,同一程序集内可以访问
    internal string internalField = "内部字段";
    
    // protected internal - 受保护内部访问,同一程序集或派生类可以访问
    protected internal string protectedInternalField = "受保护内部字段";
    
    // private protected - 私有受保护访问,同一程序集内的派生类可以访问
    private protected string privateProtectedField = "私有受保护字段";
    
    public void DemonstrateAccess()
    {
        // 在类内部可以访问所有成员
        Console.WriteLine(PublicField);
        Console.WriteLine(privateField);
        Console.WriteLine(protectedField);
        Console.WriteLine(internalField);
        Console.WriteLine(protectedInternalField);
        Console.WriteLine(privateProtectedField);
    }
}

// 在同一程序集的其他类中
public class OtherClass
{
    public void TestAccess()
    {
        var demo = new AccessModifierDemo();
        
        Console.WriteLine(demo.PublicField);        // ✓ 可以访问
        // Console.WriteLine(demo.privateField);    // ✗ 编译错误
        // Console.WriteLine(demo.protectedField);  // ✗ 编译错误
        Console.WriteLine(demo.internalField);      // ✓ 可以访问
        Console.WriteLine(demo.protectedInternalField); // ✓ 可以访问
        // Console.WriteLine(demo.privateProtectedField); // ✗ 编译错误
    }
}

构造函数

基本构造函数

csharp
public class Book
{
    private string title;
    private string author;
    private int pages;
    private decimal price;
    
    // 默认构造函数
    public Book()
    {
        title = "未知";
        author = "未知";
        pages = 0;
        price = 0.0m;
        Console.WriteLine("调用默认构造函数");
    }
    
    // 带参数的构造函数
    public Book(string title, string author)
    {
        this.title = title;
        this.author = author;
        this.pages = 0;
        this.price = 0.0m;
        Console.WriteLine("调用两参数构造函数");
    }
    
    // 完整参数构造函数
    public Book(string title, string author, int pages, decimal price)
    {
        this.title = title;
        this.author = author;
        this.pages = pages;
        this.price = price;
        Console.WriteLine("调用完整参数构造函数");
    }
    
    // 属性
    public string Title { get { return title; } set { title = value; } }
    public string Author { get { return author; } set { author = value; } }
    public int Pages { get { return pages; } set { pages = value; } }
    public decimal Price { get { return price; } set { price = value; } }
    
    public void DisplayInfo()
    {
        Console.WriteLine($"《{Title}》- {Author}, {Pages}页, ¥{Price}");
    }
}

// 使用不同的构造函数
static void ConstructorDemo()
{
    // 使用默认构造函数
    Book book1 = new Book();
    book1.DisplayInfo();
    
    // 使用两参数构造函数
    Book book2 = new Book("C# 编程指南", "微软");
    book2.Pages = 500;
    book2.Price = 89.90m;
    book2.DisplayInfo();
    
    // 使用完整参数构造函数
    Book book3 = new Book("设计模式", "GoF", 395, 79.00m);
    book3.DisplayInfo();
}

构造函数链调用

csharp
public class Rectangle
{
    private double width;
    private double height;
    
    // 默认构造函数,调用两参数构造函数
    public Rectangle() : this(1.0, 1.0)
    {
        Console.WriteLine("默认构造函数");
    }
    
    // 单参数构造函数(正方形),调用两参数构造函数
    public Rectangle(double side) : this(side, side)
    {
        Console.WriteLine("正方形构造函数");
    }
    
    // 两参数构造函数(基础构造函数)
    public Rectangle(double width, double height)
    {
        this.width = width;
        this.height = height;
        Console.WriteLine($"矩形构造函数: {width} x {height}");
    }
    
    public double Width { get { return width; } }
    public double Height { get { return height; } }
    
    public double Area => width * height;
    public double Perimeter => 2 * (width + height);
    
    public void DisplayInfo()
    {
        Console.WriteLine($"矩形: {Width} x {Height}, 面积: {Area}, 周长: {Perimeter}");
    }
}

static void ConstructorChainingDemo()
{
    Console.WriteLine("创建默认矩形:");
    Rectangle rect1 = new Rectangle();
    rect1.DisplayInfo();
    
    Console.WriteLine("\n创建正方形:");
    Rectangle rect2 = new Rectangle(5.0);
    rect2.DisplayInfo();
    
    Console.WriteLine("\n创建矩形:");
    Rectangle rect3 = new Rectangle(4.0, 6.0);
    rect3.DisplayInfo();
}

静态构造函数

csharp
public class DatabaseConnection
{
    private static string connectionString;
    private static int maxConnections;
    
    // 静态构造函数 - 只执行一次
    static DatabaseConnection()
    {
        Console.WriteLine("初始化数据库配置...");
        connectionString = "Server=localhost;Database=MyDB;";
        maxConnections = 100;
        Console.WriteLine("数据库配置初始化完成");
    }
    
    // 实例构造函数
    public DatabaseConnection()
    {
        Console.WriteLine("创建数据库连接实例");
    }
    
    public static string ConnectionString => connectionString;
    public static int MaxConnections => maxConnections;
    
    public void Connect()
    {
        Console.WriteLine($"连接到数据库: {connectionString}");
    }
}

static void StaticConstructorDemo()
{
    Console.WriteLine("程序开始");
    
    // 第一次访问类时,静态构造函数被调用
    Console.WriteLine($"最大连接数: {DatabaseConnection.MaxConnections}");
    
    // 创建实例
    DatabaseConnection conn1 = new DatabaseConnection();
    DatabaseConnection conn2 = new DatabaseConnection();
    
    // 静态构造函数不会再次执行
    conn1.Connect();
    conn2.Connect();
}

析构函数和资源管理

析构函数

csharp
public class FileManager
{
    private string fileName;
    private bool isDisposed = false;
    
    public FileManager(string fileName)
    {
        this.fileName = fileName;
        Console.WriteLine($"FileManager 创建: {fileName}");
    }
    
    // 析构函数(终结器)
    ~FileManager()
    {
        Console.WriteLine($"FileManager 析构: {fileName}");
        Dispose(false);
    }
    
    // 实现 IDisposable 接口
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);  // 告诉 GC 不需要调用析构函数
    }
    
    protected virtual void Dispose(bool disposing)
    {
        if (!isDisposed)
        {
            if (disposing)
            {
                // 释放托管资源
                Console.WriteLine($"释放托管资源: {fileName}");
            }
            
            // 释放非托管资源
            Console.WriteLine($"释放非托管资源: {fileName}");
            
            isDisposed = true;
        }
    }
    
    public void ProcessFile()
    {
        if (isDisposed)
            throw new ObjectDisposedException(nameof(FileManager));
            
        Console.WriteLine($"处理文件: {fileName}");
    }
}

static void ResourceManagementDemo()
{
    // 使用 using 语句自动释放资源
    using (var fileManager = new FileManager("document.txt"))
    {
        fileManager.ProcessFile();
    }  // 这里自动调用 Dispose()
    
    // 手动管理资源
    var fileManager2 = new FileManager("data.txt");
    try
    {
        fileManager2.ProcessFile();
    }
    finally
    {
        fileManager2.Dispose();
    }
    
    // 强制垃圾回收以演示析构函数
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

属性

自动属性

csharp
public class Product
{
    // 自动属性 - 编译器自动生成私有字段
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Stock { get; set; }
    
    // 只读自动属性
    public DateTime CreatedDate { get; }
    
    // 带初始值的自动属性
    public bool IsActive { get; set; } = true;
    
    // 私有 setter 的自动属性
    public string ProductId { get; private set; }
    
    public Product(string name, decimal price)
    {
        ProductId = Guid.NewGuid().ToString();
        Name = name;
        Price = price;
        CreatedDate = DateTime.Now;
    }
}

完整属性

csharp
public class BankAccount
{
    private decimal balance;
    private string accountNumber;
    private List<string> transactionHistory;
    
    public BankAccount(string accountNumber, decimal initialBalance = 0)
    {
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
        this.transactionHistory = new List<string>();
        AddTransaction($"账户开户,初始余额: {initialBalance:C}");
    }
    
    // 只读属性
    public string AccountNumber 
    { 
        get { return accountNumber; } 
    }
    
    // 带验证的属性
    public decimal Balance 
    { 
        get { return balance; } 
        private set 
        { 
            if (value < 0)
                throw new ArgumentException("余额不能为负数");
            balance = value; 
        } 
    }
    
    // 计算属性
    public string BalanceStatus 
    { 
        get 
        { 
            if (balance > 10000) return "富裕";
            if (balance > 1000) return "正常";
            if (balance > 0) return "紧张";
            return "透支";
        } 
    }
    
    // 只读集合属性
    public IReadOnlyList<string> TransactionHistory 
    { 
        get { return transactionHistory.AsReadOnly(); } 
    }
    
    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("存款金额必须大于0");
            
        Balance += amount;
        AddTransaction($"存款: +{amount:C}, 余额: {Balance:C}");
    }
    
    public bool Withdraw(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("取款金额必须大于0");
            
        if (amount > Balance)
        {
            AddTransaction($"取款失败: -{amount:C}, 余额不足");
            return false;
        }
        
        Balance -= amount;
        AddTransaction($"取款: -{amount:C}, 余额: {Balance:C}");
        return true;
    }
    
    private void AddTransaction(string transaction)
    {
        string timestampedTransaction = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {transaction}";
        transactionHistory.Add(timestampedTransaction);
    }
    
    public void DisplayAccountInfo()
    {
        Console.WriteLine($"账号: {AccountNumber}");
        Console.WriteLine($"余额: {Balance:C} ({BalanceStatus})");
        Console.WriteLine($"交易记录数: {TransactionHistory.Count}");
    }
    
    public void DisplayTransactionHistory(int count = 5)
    {
        Console.WriteLine($"最近 {count} 条交易记录:");
        var recentTransactions = transactionHistory.TakeLast(count);
        foreach (string transaction in recentTransactions)
        {
            Console.WriteLine($"  {transaction}");
        }
    }
}

静态成员

静态字段和方法

csharp
public class MathUtils
{
    // 静态常量
    public const double PI = 3.14159265359;
    
    // 静态只读字段
    public static readonly double E = 2.71828182846;
    
    // 静态字段
    private static int calculationCount = 0;
    
    // 静态属性
    public static int CalculationCount 
    { 
        get { return calculationCount; } 
    }
    
    // 静态方法
    public static double CalculateCircleArea(double radius)
    {
        calculationCount++;
        return PI * radius * radius;
    }
    
    public static double CalculateCircleCircumference(double radius)
    {
        calculationCount++;
        return 2 * PI * radius;
    }
    
    public static double Power(double baseValue, int exponent)
    {
        calculationCount++;
        double result = 1;
        for (int i = 0; i < Math.Abs(exponent); i++)
        {
            result *= baseValue;
        }
        return exponent >= 0 ? result : 1 / result;
    }
    
    public static void ResetCalculationCount()
    {
        calculationCount = 0;
    }
    
    public static void DisplayStatistics()
    {
        Console.WriteLine($"总计算次数: {CalculationCount}");
    }
}

// 静态类 - 只能包含静态成员
public static class StringExtensions
{
    public static bool IsValidEmail(this string email)
    {
        return !string.IsNullOrWhiteSpace(email) && 
               email.Contains("@") && 
               email.Contains(".");
    }
    
    public static string Reverse(this string input)
    {
        if (string.IsNullOrEmpty(input))
            return input;
            
        char[] chars = input.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }
    
    public static int WordCount(this string input)
    {
        if (string.IsNullOrWhiteSpace(input))
            return 0;
            
        return input.Split(new char[] { ' ', '\t', '\n', '\r' }, 
                          StringSplitOptions.RemoveEmptyEntries).Length;
    }
}

static void StaticMemberDemo()
{
    // 使用静态方法
    double area = MathUtils.CalculateCircleArea(5.0);
    double circumference = MathUtils.CalculateCircleCircumference(5.0);
    double power = MathUtils.Power(2, 8);
    
    Console.WriteLine($"圆面积: {area:F2}");
    Console.WriteLine($"圆周长: {circumference:F2}");
    Console.WriteLine($"2的8次方: {power}");
    
    MathUtils.DisplayStatistics();
    
    // 使用扩展方法
    string email = "user@example.com";
    string text = "Hello World";
    
    Console.WriteLine($"'{email}' 是有效邮箱: {email.IsValidEmail()}");
    Console.WriteLine($"'{text}' 反转: '{text.Reverse()}'");
    Console.WriteLine($"'{text}' 单词数: {text.WordCount()}");
}

实践示例

示例 1:图书管理系统

csharp
using System;
using System.Collections.Generic;
using System.Linq;

public class Book
{
    private static int nextId = 1;
    
    public int Id { get; private set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public string ISBN { get; set; }
    public DateTime PublishDate { get; set; }
    public decimal Price { get; set; }
    public bool IsAvailable { get; private set; }
    public DateTime? BorrowDate { get; private set; }
    public string BorrowerName { get; private set; }
    
    public Book(string title, string author, string isbn, DateTime publishDate, decimal price)
    {
        Id = nextId++;
        Title = title;
        Author = author;
        ISBN = isbn;
        PublishDate = publishDate;
        Price = price;
        IsAvailable = true;
    }
    
    public bool Borrow(string borrowerName)
    {
        if (!IsAvailable)
            return false;
            
        IsAvailable = false;
        BorrowDate = DateTime.Now;
        BorrowerName = borrowerName;
        return true;
    }
    
    public void Return()
    {
        IsAvailable = true;
        BorrowDate = null;
        BorrowerName = null;
    }
    
    public override string ToString()
    {
        string status = IsAvailable ? "可借" : $"已借出 (借阅人: {BorrowerName})";
        return $"[{Id}] 《{Title}》- {Author} ({PublishDate.Year}) - {status}";
    }
}

public class Library
{
    private List<Book> books;
    private string libraryName;
    
    public Library(string name)
    {
        libraryName = name;
        books = new List<Book>();
    }
    
    public string Name => libraryName;
    public int TotalBooks => books.Count;
    public int AvailableBooks => books.Count(b => b.IsAvailable);
    public int BorrowedBooks => books.Count(b => !b.IsAvailable);
    
    public void AddBook(Book book)
    {
        books.Add(book);
        Console.WriteLine($"添加图书: {book.Title}");
    }
    
    public Book FindBookById(int id)
    {
        return books.FirstOrDefault(b => b.Id == id);
    }
    
    public List<Book> SearchBooks(string keyword)
    {
        return books.Where(b => 
            b.Title.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
            b.Author.Contains(keyword, StringComparison.OrdinalIgnoreCase))
            .ToList();
    }
    
    public bool BorrowBook(int bookId, string borrowerName)
    {
        var book = FindBookById(bookId);
        if (book == null)
        {
            Console.WriteLine("图书不存在");
            return false;
        }
        
        if (book.Borrow(borrowerName))
        {
            Console.WriteLine($"{borrowerName} 成功借阅《{book.Title}》");
            return true;
        }
        else
        {
            Console.WriteLine($"《{book.Title}》已被借出");
            return false;
        }
    }
    
    public bool ReturnBook(int bookId)
    {
        var book = FindBookById(bookId);
        if (book == null)
        {
            Console.WriteLine("图书不存在");
            return false;
        }
        
        if (!book.IsAvailable)
        {
            string borrowerName = book.BorrowerName;
            book.Return();
            Console.WriteLine($"{borrowerName} 成功归还《{book.Title}》");
            return true;
        }
        else
        {
            Console.WriteLine($"《{book.Title}》未被借出");
            return false;
        }
    }
    
    public void DisplayAllBooks()
    {
        Console.WriteLine($"\n=== {libraryName} 图书列表 ===");
        if (books.Count == 0)
        {
            Console.WriteLine("暂无图书");
            return;
        }
        
        foreach (var book in books.OrderBy(b => b.Id))
        {
            Console.WriteLine(book);
        }
    }
    
    public void DisplayStatistics()
    {
        Console.WriteLine($"\n=== {libraryName} 统计信息 ===");
        Console.WriteLine($"总图书数: {TotalBooks}");
        Console.WriteLine($"可借图书: {AvailableBooks}");
        Console.WriteLine($"已借图书: {BorrowedBooks}");
        
        if (BorrowedBooks > 0)
        {
            Console.WriteLine("\n已借出图书:");
            var borrowedBooks = books.Where(b => !b.IsAvailable);
            foreach (var book in borrowedBooks)
            {
                Console.WriteLine($"  {book}");
            }
        }
    }
}

static void LibrarySystemDemo()
{
    // 创建图书馆
    var library = new Library("市中心图书馆");
    
    // 添加图书
    library.AddBook(new Book("C# 编程指南", "微软", "978-0134685991", 
                            new DateTime(2021, 3, 15), 89.90m));
    library.AddBook(new Book("设计模式", "GoF", "978-0201633610", 
                            new DateTime(1994, 10, 31), 79.00m));
    library.AddBook(new Book("代码整洁之道", "Robert Martin", "978-0132350884", 
                            new DateTime(2008, 8, 1), 69.00m));
    
    // 显示所有图书
    library.DisplayAllBooks();
    
    // 借阅图书
    library.BorrowBook(1, "张三");
    library.BorrowBook(2, "李四");
    library.BorrowBook(1, "王五");  // 尝试借阅已借出的图书
    
    // 显示统计信息
    library.DisplayStatistics();
    
    // 搜索图书
    Console.WriteLine("\n搜索结果 (关键词: 'C#'):");
    var searchResults = library.SearchBooks("C#");
    foreach (var book in searchResults)
    {
        Console.WriteLine(book);
    }
    
    // 归还图书
    library.ReturnBook(1);
    
    // 再次显示统计信息
    library.DisplayStatistics();
}

示例 2:银行账户系统

csharp
using System;
using System.Collections.Generic;

public abstract class BankAccount
{
    private static int nextAccountNumber = 1000;
    protected decimal balance;
    protected List<Transaction> transactions;
    
    public string AccountNumber { get; private set; }
    public string AccountHolderName { get; set; }
    public DateTime CreatedDate { get; private set; }
    public decimal Balance => balance;
    
    protected BankAccount(string accountHolderName, decimal initialDeposit = 0)
    {
        AccountNumber = $"ACC{nextAccountNumber++}";
        AccountHolderName = accountHolderName;
        CreatedDate = DateTime.Now;
        balance = initialDeposit;
        transactions = new List<Transaction>();
        
        if (initialDeposit > 0)
        {
            AddTransaction(TransactionType.Deposit, initialDeposit, "开户存款");
        }
    }
    
    public virtual bool Deposit(decimal amount, string description = "存款")
    {
        if (amount <= 0)
            return false;
            
        balance += amount;
        AddTransaction(TransactionType.Deposit, amount, description);
        return true;
    }
    
    public virtual bool Withdraw(decimal amount, string description = "取款")
    {
        if (amount <= 0 || !CanWithdraw(amount))
            return false;
            
        balance -= amount;
        AddTransaction(TransactionType.Withdrawal, amount, description);
        return true;
    }
    
    protected abstract bool CanWithdraw(decimal amount);
    
    protected void AddTransaction(TransactionType type, decimal amount, string description)
    {
        transactions.Add(new Transaction(type, amount, description, balance));
    }
    
    public IReadOnlyList<Transaction> GetTransactionHistory()
    {
        return transactions.AsReadOnly();
    }
    
    public virtual void DisplayAccountInfo()
    {
        Console.WriteLine($"账户类型: {GetType().Name}");
        Console.WriteLine($"账号: {AccountNumber}");
        Console.WriteLine($"户名: {AccountHolderName}");
        Console.WriteLine($"余额: {Balance:C}");
        Console.WriteLine($"开户日期: {CreatedDate:yyyy-MM-dd}");
    }
}

public class SavingsAccount : BankAccount
{
    public decimal InterestRate { get; set; }
    public DateTime LastInterestDate { get; private set; }
    
    public SavingsAccount(string accountHolderName, decimal initialDeposit = 0, decimal interestRate = 0.02m) 
        : base(accountHolderName, initialDeposit)
    {
        InterestRate = interestRate;
        LastInterestDate = CreatedDate;
    }
    
    protected override bool CanWithdraw(decimal amount)
    {
        return balance >= amount;  // 储蓄账户不能透支
    }
    
    public void CalculateInterest()
    {
        var daysSinceLastInterest = (DateTime.Now - LastInterestDate).Days;
        if (daysSinceLastInterest >= 30)  // 每月计息
        {
            decimal interest = balance * InterestRate / 12;  // 月利息
            Deposit(interest, "利息收入");
            LastInterestDate = DateTime.Now;
            Console.WriteLine($"计算利息: {interest:C}");
        }
    }
    
    public override void DisplayAccountInfo()
    {
        base.DisplayAccountInfo();
        Console.WriteLine($"年利率: {InterestRate:P2}");
        Console.WriteLine($"上次计息日期: {LastInterestDate:yyyy-MM-dd}");
    }
}

public class CheckingAccount : BankAccount
{
    public decimal OverdraftLimit { get; set; }
    public decimal OverdraftFee { get; set; }
    
    public CheckingAccount(string accountHolderName, decimal initialDeposit = 0, 
                          decimal overdraftLimit = 1000m, decimal overdraftFee = 35m) 
        : base(accountHolderName, initialDeposit)
    {
        OverdraftLimit = overdraftLimit;
        OverdraftFee = overdraftFee;
    }
    
    protected override bool CanWithdraw(decimal amount)
    {
        return (balance + OverdraftLimit) >= amount;  // 可以透支
    }
    
    public override bool Withdraw(decimal amount, string description = "取款")
    {
        if (amount <= 0 || !CanWithdraw(amount))
            return false;
            
        bool wasOverdrawn = balance < 0;
        balance -= amount;
        AddTransaction(TransactionType.Withdrawal, amount, description);
        
        // 如果透支,收取透支费用
        if (balance < 0 && !wasOverdrawn)
        {
            balance -= OverdraftFee;
            AddTransaction(TransactionType.Fee, OverdraftFee, "透支费用");
        }
        
        return true;
    }
    
    public override void DisplayAccountInfo()
    {
        base.DisplayAccountInfo();
        Console.WriteLine($"透支限额: {OverdraftLimit:C}");
        Console.WriteLine($"透支费用: {OverdraftFee:C}");
        Console.WriteLine($"可用余额: {(Balance + OverdraftLimit):C}");
    }
}

public enum TransactionType
{
    Deposit,
    Withdrawal,
    Fee,
    Interest
}

public class Transaction
{
    public DateTime Date { get; private set; }
    public TransactionType Type { get; private set; }
    public decimal Amount { get; private set; }
    public string Description { get; private set; }
    public decimal BalanceAfter { get; private set; }
    
    public Transaction(TransactionType type, decimal amount, string description, decimal balanceAfter)
    {
        Date = DateTime.Now;
        Type = type;
        Amount = amount;
        Description = description;
        BalanceAfter = balanceAfter;
    }
    
    public override string ToString()
    {
        string sign = Type == TransactionType.Deposit || Type == TransactionType.Interest ? "+" : "-";
        return $"{Date:yyyy-MM-dd HH:mm} | {Type} | {sign}{Amount:C} | {Description} | 余额: {BalanceAfter:C}";
    }
}

static void BankAccountSystemDemo()
{
    // 创建储蓄账户
    var savingsAccount = new SavingsAccount("张三", 5000m, 0.03m);
    Console.WriteLine("=== 储蓄账户 ===");
    savingsAccount.DisplayAccountInfo();
    
    // 存取款操作
    savingsAccount.Deposit(1000m, "工资存款");
    savingsAccount.Withdraw(500m, "生活费");
    savingsAccount.CalculateInterest();
    
    Console.WriteLine("\n储蓄账户交易记录:");
    foreach (var transaction in savingsAccount.GetTransactionHistory())
    {
        Console.WriteLine(transaction);
    }
    
    // 创建支票账户
    var checkingAccount = new CheckingAccount("李四", 2000m, 1500m, 30m);
    Console.WriteLine("\n\n=== 支票账户 ===");
    checkingAccount.DisplayAccountInfo();
    
    // 透支操作
    checkingAccount.Withdraw(3000m, "大额支出");  // 透支
    checkingAccount.Withdraw(200m, "继续支出");   // 继续透支
    
    Console.WriteLine("\n支票账户交易记录:");
    foreach (var transaction in checkingAccount.GetTransactionHistory())
    {
        Console.WriteLine(transaction);
    }
    
    Console.WriteLine("\n更新后的账户信息:");
    checkingAccount.DisplayAccountInfo();
}

本章小结

本章详细介绍了 C# 中的类和对象:

关键要点:

  • 类的定义:字段、属性、方法、构造函数的组织
  • 访问修饰符:控制成员的可见性和访问权限
  • 构造函数:对象初始化、构造函数链调用、静态构造函数
  • 属性:封装字段访问、自动属性、计算属性
  • 静态成员:类级别的数据和行为
  • 资源管理:析构函数、IDisposable 接口

面向对象原则:

  • 封装:隐藏实现细节,提供清晰的接口
  • 单一职责:每个类应该只有一个改变的理由
  • 开闭原则:对扩展开放,对修改关闭

最佳实践:

  • 合理使用访问修饰符保护数据
  • 优先使用属性而不是公共字段
  • 实现 IDisposable 接口管理资源
  • 使用构造函数确保对象的有效状态
  • 静态成员用于类级别的功能

下一步: 在下一章中,我们将学习封装和属性的高级用法,深入理解面向对象的封装特性。

延伸阅读

本站内容仅供学习和研究使用。