委托(Delegate)
事件(Event)
委托与事件的区别
文件与I/O操作
委托:类型安全的函数指针,可以像传递数据一样传递方法。
// 定义委托
public delegate int MathOperation(int a, int b);
class Program
{
static int Add(int x, int y) => x + y;
static int Subtract(int x, int y) => x - y;
static void Main()
{
MathOperation operation = Add;
int result = operation(10, 5); // 15
operation = Subtract;
result = operation(10, 5); // 5
}
}// 定义委托
public delegate bool FilterDelegate(int number);
class Program
{
static bool IsEven(int n) => n % 2 == 0;
static bool IsPositive(int n) => n > 0;
static List<int> Filter(List<int> numbers, FilterDelegate filter)
{
List<int> result = new List<int>();
foreach (int n in numbers)
{
if (filter(n)) result.Add(n);
}
return result;
}
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> evens = Filter(numbers, IsEven);
List<int> positives = Filter(numbers, IsPositive);
}
}C# 提供了泛型委托,无需自己定义:
委托类型 | 参数 | 返回值 | 示例 |
|---|---|---|---|
| 0-16个 |
|
|
| 0-16个 | 最后一个类型参数 |
|
| 1个(T) |
|
|
class Program
{
static void Main()
{
// Action:无返回值
Action<string> print = Console.WriteLine;
print("Hello");
// Func:有返回值
Func<int, int, int> add = (a, b) => a + b;
int result = add(10, 20); // 30
// Predicate:返回 bool
Predicate<int> isEven = n => n % 2 == 0;
bool even = isEven(4); // true
}
}// Lambda 语法:(参数) => 表达式或语句块
// 无参数
Action sayHello = () => Console.WriteLine("Hello");
// 单个参数(可省略括号)
Func<int, int> square = x => x * x;
// 多个参数
Func<int, int, int> add = (a, b) => a + b;
// 语句块 Lambda
Func<int, int, int> calculate = (a, b) =>
{
int sum = a + b;
int product = a * b;
return sum + product;
};
// 在 LINQ 中使用
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> evenNumbers = numbers.Where(n => n % 2 == 0).ToList();一个委托可以引用多个方法,调用时依次执行。
class Program
{
static void Method1() => Console.WriteLine("方法1");
static void Method2() => Console.WriteLine("方法2");
static void Method3() => Console.WriteLine("方法3");
static void Main()
{
Action multicast = Method1;
multicast += Method2; // 添加
multicast += Method3;
multicast(); // 输出:方法1 方法2 方法3
multicast -= Method2; // 移除
multicast(); // 输出:方法1 方法3
}
}事件:基于委托的发布-订阅机制,让对象在特定情况下通知其他对象。
发布者:触发事件的对象
订阅者:响应事件的对象
事件:发布者提供的"接口"
// 1. 事件参数类(继承 EventArgs)
public class TemperatureEventArgs : EventArgs
{
public double Temperature { get; set; }
public DateTime Time { get; set; }
public TemperatureEventArgs(double temperature)
{
Temperature = temperature;
Time = DateTime.Now;
}
}
// 2. 发布者类
public class Thermometer
{
private double _temperature;
// 定义事件(使用 EventHandler<T>)
public event EventHandler<TemperatureEventArgs> TemperatureChanged;
// 触发事件的方法
protected virtual void OnTemperatureChanged(TemperatureEventArgs e)
{
TemperatureChanged?.Invoke(this, e);
}
public void UpdateTemperature(double newTemp)
{
_temperature = newTemp;
OnTemperatureChanged(new TemperatureEventArgs(_temperature));
}
}
// 3. 订阅者类
public class Fan
{
public void OnTemperatureChanged(object sender, TemperatureEventArgs e)
{
if (e.Temperature > 30)
Console.WriteLine($"[风扇] 温度 {e.Temperature}°C,风扇打开!");
else
Console.WriteLine($"[风扇] 温度 {e.Temperature}°C,风扇关闭!");
}
}
// 4. 使用
class Program
{
static void Main()
{
Thermometer thermometer = new Thermometer();
Fan fan = new Fan();
// 订阅事件
thermometer.TemperatureChanged += fan.OnTemperatureChanged;
// 匿名方法订阅
thermometer.TemperatureChanged += (sender, e) =>
{
Console.WriteLine($"[日志] 温度:{e.Temperature}°C");
};
// 触发事件
thermometer.UpdateTemperature(32.5);
}
}// 事件参数
public class OrderEventArgs : EventArgs
{
public int OrderId { get; }
public string CustomerName { get; }
public decimal Amount { get; }
public OrderEventArgs(int orderId, string customerName, decimal amount)
{
OrderId = orderId;
CustomerName = customerName;
Amount = amount;
}
}
// 发布者
public class OrderService
{
public event EventHandler<OrderEventArgs> OrderCreated;
public event EventHandler<OrderEventArgs> OrderCompleted;
protected virtual void OnOrderCreated(OrderEventArgs e)
=> OrderCreated?.Invoke(this, e);
protected virtual void OnOrderCompleted(OrderEventArgs e)
=> OrderCompleted?.Invoke(this, e);
public void CreateOrder(int orderId, string customer, decimal amount)
{
OnOrderCreated(new OrderEventArgs(orderId, customer, amount));
// 处理订单...
OnOrderCompleted(new OrderEventArgs(orderId, customer, amount));
}
}
// 订阅者
public class EmailService
{
public void OnOrderCreated(object sender, OrderEventArgs e)
=> Console.WriteLine($"[邮件] 订单 {e.OrderId} 已创建");
public void OnOrderCompleted(object sender, OrderEventArgs e)
=> Console.WriteLine($"[邮件] 订单 {e.OrderId} 已完成");
}
// 使用
class Program
{
static void Main()
{
OrderService service = new OrderService();
EmailService email = new EmailService();
service.OrderCreated += email.OnOrderCreated;
service.OrderCompleted += email.OnOrderCompleted;
service.CreateOrder(1001, "张三", 299.99m);
}
}特性 | 委托(Delegate) | 事件(Event) |
|---|---|---|
定义 |
|
|
用途 | 传递方法作为参数 | 发布-订阅通知 |
调用者 | 任何可以访问的地方 | 只能在定义类内部 |
外部调用 | ✅ 可以 | ❌ 不可以(编译错误) |
多播 | 支持(+= / -=) | 支持(+= / -=) |
使用场景 | 回调、LINQ、异步 | UI事件、消息通知 |
public class Example
{
// 委托:外部可调用
public Action<string> DelegateAction;
// 事件:外部只能订阅/取消
public event Action<string> EventAction;
public void Test()
{
DelegateAction?.Invoke("Hello"); // ✅ 可以
EventAction?.Invoke("Hello"); // ✅ 可以(类内部)
}
}
class Program
{
static void Main()
{
Example ex = new Example();
ex.DelegateAction += Console.WriteLine; // ✅ 订阅委托
ex.EventAction += Console.WriteLine; // ✅ 订阅事件
ex.DelegateAction("委托调用"); // ✅ 可以调用委托
// ex.EventAction("事件调用"); // ❌ 编译错误
}
}using System.IO; // 核心 I/O 类
using System.Text; // 编码支持
using System.Threading.Tasks; // 异步操作类名 | 用途 | 特点 |
|---|---|---|
| 文件操作(静态方法) | 简单快速,适合小文件 |
| 文件信息(实例方法) | 更灵活,适合多次操作 |
| 目录操作(静态方法) | 创建、删除、遍历目录 |
| 目录信息(实例方法) | 详细目录信息 |
| 路径处理 | 跨平台路径操作 |
| 文件流 | 底层读写,适合大文件 |
| 文本读写 | 处理文本文件 |
| 二进制读写 | 处理二进制数据 |
// 快速读写(适合小文件)
string path = "example.txt";
// 写入文本
File.WriteAllText(path, "Hello, C#!");
// 读取所有文本
string content = File.ReadAllText(path);
// 按行写入
string[] lines = { "行1", "行2", "行3" };
File.WriteAllLines("lines.txt", lines);
// 按行读取
string[] readLines = File.ReadAllLines("lines.txt");
// 追加文本
File.AppendAllText(path, "\n追加的内容");
// 使用 StreamReader/Writer(适合大文件)
using (StreamWriter writer = new StreamWriter(path))
{
for (int i = 0; i < 10; i++)
{
writer.WriteLine($"第 {i + 1} 行");
}
}
using (StreamReader reader = new StreamReader(path))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
// 指定编码
using (StreamReader reader = new StreamReader(path, Encoding.UTF8))
{
string content = reader.ReadToEnd();
}特性 | using 语句块 | using 声明 |
|---|---|---|
语法 |
|
|
作用域 | 大括号 | 当前代码块 |
释放时机 | 离开大括号时 | 离开当前代码块时 |
C#版本 | 1.0+ | 8.0+ |
// using 语句块(传统)
using (StreamWriter writer = new StreamWriter(path))
{
writer.WriteLine("Hello");
} // 离开块时释放
// using 声明(C# 8.0+)
using StreamWriter writer = new StreamWriter(path);
writer.WriteLine("Hello");
// 当前方法结束时释放string path = @"C:\Projects\MyApp\data\settings.json";
Console.WriteLine($"目录:{Path.GetDirectoryName(path)}");
Console.WriteLine($"文件名:{Path.GetFileName(path)}");
Console.WriteLine($"扩展名:{Path.GetExtension(path)}");
Console.WriteLine($"文件名(无扩展名):{Path.GetFileNameWithoutExtension(path)}");
// 组合路径
string combined = Path.Combine(@"C:\Projects", "data", "settings.json");
// 获取临时文件
string tempFile = Path.GetTempFileName();
// 获取应用程序目录
string appDir = AppDomain.CurrentDomain.BaseDirectory;string path = @"C:\Temp\MyApp";
// 检查目录是否存在
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
// 获取子目录
string[] subDirs = Directory.GetDirectories(path);
// 获取所有文件(递归)
string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
// 删除目录
Directory.Delete(path, true);FileInfo fileInfo = new FileInfo("example.txt");
Console.WriteLine($"文件名:{fileInfo.Name}");
Console.WriteLine($"大小:{fileInfo.Length} bytes");
Console.WriteLine($"创建时间:{fileInfo.CreationTime}");
Console.WriteLine($"最后修改:{fileInfo.LastWriteTime}");
Console.WriteLine($"只读:{fileInfo.IsReadOnly}");
// 复制文件
fileInfo.CopyTo("example_copy.txt");
// 删除文件
fileInfo.Delete();string path = "data.bin";
// 写入二进制数据
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
writer.Write(10); // int
writer.Write(3.14); // double
writer.Write(true); // bool
writer.Write("Hello"); // string
writer.Write(new byte[] { 1, 2, 3 }); // byte[]
}
// 读取二进制数据(按相同顺序)
using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open)))
{
int intValue = reader.ReadInt32();
double doubleValue = reader.ReadDouble();
bool boolValue = reader.ReadBoolean();
string stringValue = reader.ReadString();
byte[] bytes = reader.ReadBytes(3);
}async Task WriteFileAsync(string path, string content)
{
byte[] data = Encoding.UTF8.GetBytes(content);
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
await fs.WriteAsync(data, 0, data.Length);
}
}
async Task<string> ReadFileAsync(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[fs.Length];
await fs.ReadAsync(buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer);
}
}
async Task CopyFileAsync(string source, string destination)
{
using (FileStream sourceStream = File.OpenRead(source))
using (FileStream destStream = File.Create(destination))
{
await sourceStream.CopyToAsync(destStream);
}
}// ✅ 使用 using 确保资源释放
using (var writer = new StreamWriter("file.txt"))
{
writer.WriteLine("Hello");
}
// ✅ 检查文件是否存在
if (File.Exists(path))
{
string content = File.ReadAllText(path);
}
// ✅ 使用 try-catch 处理异常
try
{
File.WriteAllText(path, content);
}
catch (IOException ex)
{
Console.WriteLine($"文件操作失败:{ex.Message}");
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"权限不足:{ex.Message}");
}
// ✅ 使用 Path.Combine 组合路径
string fullPath = Path.Combine(appDirectory, "data", "file.txt");
// ❌ 避免:直接拼接路径
// string path = appDir + "\\" + "data" + "\\" + "file.txt";
// ❌ 避免:不释放资源
// StreamReader reader = new StreamReader(path);
// string content = reader.ReadToEnd(); // 忘记关闭using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
public class AppConfig
{
public string AppName { get; set; } = "MyApp";
public string Version { get; set; } = "1.0.0";
public int MaxRetries { get; set; } = 3;
public bool DebugMode { get; set; } = true;
public Dictionary<string, string> ConnectionStrings { get; set; } = new();
}
public class ConfigManager
{
private readonly string _configPath;
private AppConfig _config;
public ConfigManager(string configPath = "appsettings.json")
{
_configPath = configPath;
LoadOrCreate();
}
public AppConfig Config => _config;
private void LoadOrCreate()
{
if (File.Exists(_configPath))
Load();
else
CreateDefault();
}
private void Load()
{
try
{
string json = File.ReadAllText(_configPath);
_config = JsonSerializer.Deserialize<AppConfig>(json);
}
catch (Exception ex)
{
Console.WriteLine($"加载配置失败:{ex.Message}");
CreateDefault();
}
}
private void CreateDefault()
{
_config = new AppConfig();
Save();
}
public void Save()
{
try
{
string json = JsonSerializer.Serialize(_config, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText(_configPath, json);
}
catch (Exception ex)
{
Console.WriteLine($"保存配置失败:{ex.Message}");
}
}
}类型 | 定义 | 用途 |
|---|---|---|
自定义委托 |
| 自定义回调 |
| 无返回值 | 执行操作 |
| 有返回值 | 计算并返回 |
| 返回 | 条件判断 |
Lambda |
| 简洁匿名方法 |
步骤 | 代码 |
|---|---|
定义事件参数 |
|
定义事件 |
|
触发事件 |
|
订阅事件 |
|
取消订阅 |
|
操作 | 方法 |
|---|---|
读写全部文本 |
|
读写全部行 |
|
逐行读取 |
|
逐行写入 |
|
二进制读写 |
|
异步读写 |
|
路径操作 |
|
目录操作 |
|