【C#学习Day15笔记】拆箱装箱、 Equals与== 、文件读取IO

发布于:2025-08-02 ⋅ 阅读:(12) ⋅ 点赞:(0)

前言

在C#第15天的学习中,我深入探索了类型转换机制对象比较原理文件操作技术三大核心主题。这些知识是构建高效、健壮程序的关键基础。本文完整保留我的课堂实践代码和命名体系,通过结构化梳理帮助大家掌握这些核心概念。所有代码示例均来自我的实际操作,包含从基础到进阶的完整学习过程!


一、拆箱装箱:值类型与引用类型的转换

1. 基础概念与实现

// 装箱:值类型 → 引用类型
int a = 1;
object b = a;  // 装箱操作

// 拆箱:引用类型 → 值类型
object c = 1;
int d = (int)c; // 拆箱操作

2. 内存机制解析


3. 性能影响与最佳实践

操作 性能开销 使用建议
装箱 高(内存分配+数据复制) 避免在循环中使用
拆箱 中(类型检查+数据复制) 确保类型兼容
泛型集合 无(避免装箱拆箱) 优先使用List

二、Equals与==:对象比较的深层解析

1. 值类型比较

int x = 10;
int y = 10;

// == 运算符比较
Console.WriteLine(x == y); // true

// Equals方法比较
Console.WriteLine(x.Equals(y)); // true

2. 引用类型比较

class Person
{
    public int Age { get; set; }
    public string Name { get; set; }
    
    public Person(int age, string name)
    {
        Age = age;
        Name = name;
    }
}

Person p1 = new Person(18, "张三");
Person p2 = new Person(18, "张三");

// == 默认比较引用地址
Console.WriteLine(p1 == p2); // false

// Equals默认比较引用地址
Console.WriteLine(p1.Equals(p2)); // false

3. 重写Equals实现值比较

class Person
{
    // ...其他代码同上...
    
    // 重写Equals方法
    public override bool Equals(object obj)
    {
        // 类型检查
        if (obj == null || GetType() != obj.GetType())
            return false;
        
        Person p = (Person)obj;
        return Age == p.Age && Name == p.Name;
    }
    
    // 重写GetHashCode(推荐与Equals一起重写)
    public override int GetHashCode()
    {
        return Age.GetHashCode() ^ Name.GetHashCode();
    }
}

// 使用重写后的Equals
Console.WriteLine(p1.Equals(p2)); // true

4. 比较操作决策表

比较场景 推荐方式 注意事项
值类型相等 == 或 Equals 两者行为相同
引用类型地址相等 == 默认行为
引用类型值相等 重写 Equals 需同时重写 GetHashCode
字符串内容相等 == 或 Equals 字符串已特殊处理

三、文件IO操作:数据持久化技术

1. FileStream基础操作

// 创建文件信息对象
FileInfo fi = new FileInfo("data.txt");

// 写入文件
using (FileStream writeStream = fi.OpenWrite())
{
    byte[] data = { 65, 66, 67, 68, 69 };
    writeStream.Write(data, 0, data.Length);
}

// 读取文件
using (FileStream readStream = fi.OpenRead())
{
    byte[] buffer = new byte[fi.Length];
    int bytesRead = readStream.Read(buffer, 0, buffer.Length);
    
    foreach (byte b in buffer)
    {
        Console.WriteLine(b);
    }
}

2. StreamReader/Writer高级操作

// 获取动态路径
string path = Path.Combine(Directory.GetCurrentDirectory(), "data.txt");

// 写入数据
using (StreamWriter sw = new StreamWriter(path, true)) // true表示追加模式
{
    sw.WriteLine("张三今天打游戏了");
    sw.WriteLine("李四今天游泳了");
    sw.WriteLine("王五今天吃饭了");
}

// 读取数据
using (StreamReader sr = new StreamReader(path))
{
    string content = sr.ReadToEnd();
    string[] lines = content.Split('\n');
    
    foreach (string line in lines)
    {
        if (line.Contains("张三"))
        {
            Console.WriteLine("找到张三的记录");
        }
    }
}

3. 文件操作最佳实践

  1. 路径处理​:

    • 使用Path.Combine()构建路径
    • 使用Directory.GetCurrentDirectory()获取当前目录
    • 避免硬编码绝对路径
  2. 资源管理​:

    • 始终使用using语句确保资源释放
    • 处理文件不存在异常
    • 检查磁盘空间
  3. 性能优化​:

    • 使用缓冲区减少IO操作
    • 异步读写大文件
    • 批量处理小文件

四、综合案例:学生成绩管理系统

1. 学生类实现

class Student
{
    public string Name { get; set; }
    public int Score { get; set; }
    
    public Student(string name, int score)
    {
        Name = name;
        Score = score;
    }
    
    // 重写Equals实现值比较
    public override bool Equals(object obj)
    {
        if (obj is Student other)
            return Name == other.Name && Score == other.Score;
        return false;
    }
    
    public override int GetHashCode()
    {
        return Name.GetHashCode() ^ Score;
    }
}

2. 文件存储与加载

class ScoreManager
{
    private List<Student> students = new List<Student>();
    private string filePath;
    
    public ScoreManager(string path)
    {
        filePath = path;
        LoadData();
    }
    
    // 加载数据
    private void LoadData()
    {
        if (File.Exists(filePath))
        {
            using (StreamReader sr = new StreamReader(filePath))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    string[] parts = line.Split(',');
                    if (parts.Length == 2 && int.TryParse(parts[1], out int score))
                    {
                        students.Add(new Student(parts[0], score));
                    }
                }
            }
        }
    }
    
    // 保存数据
    public void SaveData()
    {
        using (StreamWriter sw = new StreamWriter(filePath))
        {
            foreach (Student s in students)
            {
                sw.WriteLine($"{s.Name},{s.Score}");
            }
        }
    }
    
    // 添加学生
    public void AddStudent(Student student)
    {
        students.Add(student);
    }
    
    // 查找学生
    public Student FindStudent(string name)
    {
        return students.Find(s => s.Name == name);
    }
}

3. 系统使用示例

// 初始化管理器
ScoreManager manager = new ScoreManager("scores.txt");

// 添加学生
manager.AddStudent(new Student("张三", 90));
manager.AddStudent(new Student("李四", 85));

// 保存数据
manager.SaveData();

// 查找学生
Student found = manager.FindStudent("张三");
if (found != null)
{
    Console.WriteLine($"找到学生: {found.Name}, 成绩: {found.Score}");
}

// 比较学生
Student s1 = new Student("王五", 80);
Student s2 = new Student("王五", 80);
Console.WriteLine(s1.Equals(s2)); // true

学习总结与进阶建议

核心知识图谱


关键编程原则

  1. 类型转换​:

    • 避免不必要的装箱拆箱
    • 使用泛型集合替代非泛型集合
    • 优先使用asis进行安全转换
  2. 对象比较​:

    • 值类型直接使用==
    • 引用类型按需重写Equals
    • 重写Equals时同步重写GetHashCode
  3. 文件操作​:

    • 使用using确保资源释放
    • 处理所有可能的IO异常
    • 使用相对路径增强可移植性

实战项目建议

  1. 类型系统应用​:

    • 实现高性能数值计算库
    • 开发类型安全的数据容器
    • 创建泛型缓存系统
  2. 对象比较实践​:

    • 实现深度比较工具
    • 开发自定义集合类
    • 创建对象差异检测器
  3. 文件IO实战​:

    • 开发配置管理系统
    • 实现数据导入导出功能
    • 创建日志记录模块

编程箴言
"理解类型转换是性能优化的基础,掌握对象比较是正确性的保障,善用文件IO是数据持久化的关键"