跳转至

委托、事件与文件 IO 复习#

对应笔记:委托与 Lambda事件Array 数组方法文件 IO 概览File 类与 FileInfo 类StreamReader 与 StreamWriterFileStream 字节流BinaryReader 与 BinaryWriter 建议用时:60 分钟。


一、选择题#

1. 什么是委托(Delegate)?

  • A. 一种数据类型,用来存储方法
  • B. 一种循环结构
  • C. 一个类
  • D. 一种异常类型
答案

A。委托是"函数的数据类型",可以把方法赋值给委托变量,像调用方法一样调用。C# 中函数也是数据。

2. Func<int, bool> 委托的含义是?

  • A. 无参返回 bool
  • B. 接收 int 参数,返回 bool
  • C. 接收两个参数
  • D. 无返回值
答案

B。Func 最后一个泛型参数是返回值类型,前面的都是参数类型。Func<int, bool> = 接收 int、返回 bool。无返回值的用 Action

3. 委托变量为 null 时直接调用会?

  • A. 返回 null
  • B. 抛 NullReferenceException
  • C. 自动忽略
  • D. 返回 false
答案

B。安全做法:del?.Invoke(args)(空条件运算符)或先判断 if (del != null)

4. 事件(event)与普通委托的区别,错误的是?

  • A. 事件外部只能订阅(+=)或取消(-=)
  • B. 事件只能在声明类内部触发
  • C. 事件外部可以随意触发
  • D. 事件用于发布-订阅模式
答案

C。事件只能在声明它的类内部触发,外部不能直接调用;外部只能 += 订阅 / -= 取消。

5. StreamReaderStreamWriter 主要用于?

  • A. 二进制数据读写
  • B. 文本数据逐行/逐字符读写
  • C. 数据库连接
  • D. 网络通信
答案

B。StreamReader/Writer 是文本流;BinaryReader/Writer 是二进制流;FileStream 是底层字节流。

6. using 语句的作用是?

  • A. 引入命名空间
  • B. 确保资源(IDisposable)在代码块结束时自动释放
  • C. 定义别名
  • D. 声明变量
答案

Busing (var r = new Resource()) { } 会在块结束时自动调用 Dispose(),即使发生异常。FileStream、StreamReader 等都实现了 IDisposable,应优先用 using。

7. File.ReadAllLines(path) 的返回值是?

  • A. string
  • B. string[](每行一个元素)
  • C. List<string>
  • D. byte[]

> [!success]- 答案 > B。ReadAllText 返回 string(整个文件);ReadAllLines 返回 string[](每行一个元素)。


二、填空题#

1. Lambda 表达式的基本格式:==_== ==== ==_== ====,如 v => v % 2 == 0

答案

(参数列表) => { 方法体 } 或简化 参数 => 表达式(单表达式可省略大括号和 return)。

2. 内置委托类型:无返回值用 ==_== ==== ==_== ====,有返回值用 ==_== ==== ==_== ====。

答案

Action&lt;参数...&gt;Func&lt;参数..., 返回值&gt;

3. 多播委托用 ==_== ==== ==_== ==== 添加方法、==_== ==== ==_== ==== 移除方法。

答案

+=-=。调用时按添加顺序依次执行所有方法。

4. 文件路径基础:以盘符开头的是 ==_== ==== ==_== ==== 路径,./ 表示 ==_== ==== ==_== ====,../ 表示 ==_== ==== ==_== ====。

答案

绝对路径;当前目录;上一级目录。

5. BinaryWriter.Write(12345) 写入的是 ==_== ==== ==_== ==== 类型数据,读取时用 ==_== ==== ==_== ==== 方法。

答案

int(整数);ReadInt32()。写入和读取的顺序、类型必须一致。

6. 文本文件读写推荐用 ==_== ==== ==_== ==== 类,二进制用 ==_== ==== ==_== ==== 类,底层字节流用 ==_== ==== ==_== ==== 类。

答案

StreamReader/StreamWriter;BinaryReader/BinaryWriter;FileStream。


三、代码分析题#

1. 写出输出结果。

public delegate void MyDel(string s);
MyDel d = (s) => Console.WriteLine("A:" + s);
d += (s) => Console.WriteLine("B:" + s);
d("hi");
d -= /* 第一个方法 */;
答案

调用 d("hi") 依次输出:

A:hi
B:hi
多播委托按添加顺序执行。移除方法后只剩 B。

2. 写出输出结果。

int[] nums = { 1, 2, 3, 4, 5, 6 };
var r1 = Array.Find(nums, n => n % 2 == 0);
var r2 = Array.FindAll(nums, n => n % 2 == 0);
var r3 = Array.Exists(nums, n => n > 10);
答案

r1 = 2(Find 返回第一个满足条件的元素);r2 = {2, 4, 6}(FindAll 返回所有满足条件的数组);r3 = false(Exists 判断是否存在)。

3. 下列代码有什么问题?

class Boiler
{
    public event Action<double> THigh;
    public void Check(double t)
    {
        if (t > 100) THigh(t);   // 这里可能有什么问题?
    }
}
答案

如果没有人订阅事件,THigh 为 null,直接调用会抛 NullReferenceException。应改为 THigh?.Invoke(t);

4. 写出读取文本文件每一行的正确代码(using 写法)。

答案
using (FileStream fs = new FileStream("data.txt", FileMode.Open, FileAccess.Read))
using (StreamReader sr = new StreamReader(fs))
{
    string line;
    while ((line = sr.ReadLine()) != null)
        Console.WriteLine(line);
}

四、编程题#

1. 定义委托,接收两个 int 返回 int,用 Lambda 实现加法并调用。

答案
Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 4));  // 7

2. 自定义事件:发布者(温度计)温度超过 100 触发报警事件,订阅者(报警器)输出"温度过高"。

答案

```csharp

> class Thermometer > { > public event Action<int> Overheat; > public void SetTemp(int t) > { > if (t > 100) Overheat?.Invoke(t); > } > } > class Alarm > { > public void Ring(int t) { Console.WriteLine($"温度过高:{t}"); } > } > // 使用 > Thermometer tm = new Thermometer(); > Alarm alarm = new Alarm(); > tm.Overheat += alarm.Ring; > tm.SetTemp(120); // 触发 → "温度过高:120" > ```

3. 用 File 类实现:追加一行文本到文件,然后读取全部行输出。

答案
string path = "data.txt";
File.AppendAllText(path, "新的一行\n");
string[] lines = File.ReadAllLines(path);
foreach (string line in lines) Console.WriteLine(line);

4. 用 Directory 类实现:判断目录是否存在,不存在则创建,并列出其中的文件。

答案
string dir = "./mydata";
if (!Directory.Exists(dir))
    Directory.CreateDirectory(dir);
string[] files = Directory.GetFiles(dir);
foreach (string f in files) Console.WriteLine(f);

5. 用 BinaryWriter 写入 int 和 string,再用 BinaryReader 读回。

答案
// 写入
using (FileStream fs = new FileStream("data.bin", FileMode.Create, FileAccess.Write))
using (BinaryWriter bw = new BinaryWriter(fs))
{
    bw.Write(12345);
    bw.Write("hello");
}
// 读取(顺序必须一致)
using (FileStream fs = new FileStream("data.bin", FileMode.Open, FileAccess.Read))
using (BinaryReader br = new BinaryReader(fs))
{
    Console.WriteLine(br.ReadInt32());   // 12345
    Console.WriteLine(br.ReadString());  // hello
}

6. 用泛型方法实现:打印任意类型数组的所有元素。

答案
public static void PrintArr`<T>`(T[] arr)
{
    foreach (T item in arr) Console.WriteLine(item);
}
PrintArr(new int[] { 1, 2, 3 });
PrintArr(new string[] { "a", "b" });

知识卡片#

委托是什么?

函数的数据类型。声明委托类型可保存方法,像调用方法一样调用。delegate 返回类型 委托名(参数列表)

Func 与 Action 的区别?

Func 有返回值(最后泛型参数是返回类型);Action 无返回值。

多播委托?

一个委托存多个方法,+= 添加、-= 移除,调用时按顺序依次执行。

委托调用的空值保护?

del?.Invoke(args) 或先判空。null 直接调用会抛 NullReferenceException。

事件的三要素?

发布者(声明并触发事件)、订阅者(提供处理方法)、事件(+= / -= 连接双方)。

事件与委托的区别?

事件只能在声明类内部触发,外部只能订阅/取消;委托可以直接调用。

File 与 FileInfo 的区别?

File 是静态类,一次性操作(File.ReadAllText);FileInfo 是实例类,多次操作同一文件或查详细信息。

FileStream 与 StreamReader 的区别?

FileStream 底层字节流;StreamReader 基于 FileStream 的文本流,逐行读写更方便。

using 语句的作用?

自动释放 IDisposable 资源(Close + Dispose),即使异常也保证释放;文件流、读写器都应使用。

二进制读写注意什么?

写入与读取的顺序、类型必须一致(Write(int) 用 ReadInt32 读回);写入后 Flush 确保落盘。


相关笔记#