本章目标
通过本章学习,你将掌握: - 委托的概念和基本使用 - 多播委托和委托链 - 匿名方法和Lambda表达式 - 事件的定义和使用 - 事件处理模式 - 观察者模式的实现 - 委托和事件的最佳实践
1. 委托基础
1.1 委托的概念
委托是一种类型,表示对具有特定签名的方法的引用。可以将委托看作是函数指针的类型安全版本。
// 声明委托类型
public delegate int MathOperation(int x, int y);
public delegate void MessageHandler(string message);
public delegate bool Predicate<T>(T item);
public delegate TResult Func<T, TResult>(T input);
// 基本委托使用示例
public class DelegateBasics
{
// 符合MathOperation委托签名的方法
public static int Add(int x, int y)
{
Console.WriteLine($"执行加法:{x} + {y}");
return x + y;
}
public static int Subtract(int x, int y)
{
Console.WriteLine($"执行减法:{x} - {y}");
return x - y;
}
public static int Multiply(int x, int y)
{
Console.WriteLine($"执行乘法:{x} × {y}");
return x * y;
}
public static int Divide(int x, int y)
{
if (y == 0)
throw new DivideByZeroException("除数不能为零");
Console.WriteLine($"执行除法:{x} ÷ {y}");
return x / y;
}
// 符合MessageHandler委托签名的方法
public static void PrintMessage(string message)
{
Console.WriteLine($"[打印] {message}");
}
public static void LogMessage(string message)
{
Console.WriteLine($"[日志] {DateTime.Now:HH:mm:ss} - {message}");
}
public static void DebugMessage(string message)
{
Console.WriteLine($"[调试] {message.ToUpper()}");
}
}
// 委托使用示例
public class DelegateDemo
{
public static void DemonstrateDelegateBasics()
{
Console.WriteLine("=== 委托基础演示 ===");
// 创建委托实例
Console.WriteLine("\n--- 基本委托使用 ---");
MathOperation operation;
// 方法1:使用new关键字
operation = new MathOperation(DelegateBasics.Add);
int result1 = operation(10, 5);
Console.WriteLine($"结果:{result1}");
// 方法2:直接赋值(推荐)
operation = DelegateBasics.Subtract;
int result2 = operation(10, 5);
Console.WriteLine($"结果:{result2}");
// 方法3:使用方法组
operation = DelegateBasics.Multiply;
int result3 = operation(10, 5);
Console.WriteLine($"结果:{result3}");
// 委托作为参数传递
Console.WriteLine("\n--- 委托作为参数 ---");
ExecuteOperation(DelegateBasics.Add, 15, 25);
ExecuteOperation(DelegateBasics.Divide, 20, 4);
// 委托数组
Console.WriteLine("\n--- 委托数组 ---");
MathOperation[] operations = {
DelegateBasics.Add,
DelegateBasics.Subtract,
DelegateBasics.Multiply,
DelegateBasics.Divide
};
int x = 12, y = 3;
foreach (MathOperation op in operations)
{
try
{
int result = op(x, y);
Console.WriteLine($"结果:{result}");
}
catch (Exception ex)
{
Console.WriteLine($"错误:{ex.Message}");
}
}
// 消息处理委托
Console.WriteLine("\n--- 消息处理委托 ---");
MessageHandler handler = DelegateBasics.PrintMessage;
handler("Hello Delegate!");
handler = DelegateBasics.LogMessage;
handler("这是一条日志消息");
handler = DelegateBasics.DebugMessage;
handler("Debug Information");
}
private static void ExecuteOperation(MathOperation operation, int x, int y)
{
try
{
int result = operation(x, y);
Console.WriteLine($"操作结果:{result}");
}
catch (Exception ex)
{
Console.WriteLine($"操作失败:{ex.Message}");
}
}
}
1.2 多播委托
// 多播委托示例
public class MulticastDelegateDemo
{
public static void DemonstrateMulticastDelegates()
{
Console.WriteLine("\n=== 多播委托演示 ===");
// 创建多播委托
Console.WriteLine("\n--- 多播委托组合 ---");
MessageHandler handler = null;
// 使用 += 添加方法
handler += DelegateBasics.PrintMessage;
handler += DelegateBasics.LogMessage;
handler += DelegateBasics.DebugMessage;
Console.WriteLine("调用多播委托:");
handler("多播委托测试消息");
// 使用 -= 移除方法
Console.WriteLine("\n--- 移除委托方法 ---");
handler -= DelegateBasics.DebugMessage;
Console.WriteLine("移除DebugMessage后:");
handler("移除后的消息");
// 委托链的顺序
Console.WriteLine("\n--- 委托链顺序 ---");
MessageHandler orderedHandler = null;
orderedHandler += msg => Console.WriteLine($"第一个:{msg}");
orderedHandler += msg => Console.WriteLine($"第二个:{msg}");
orderedHandler += msg => Console.WriteLine($"第三个:{msg}");
Console.WriteLine("按顺序执行:");
orderedHandler("顺序测试");
// 获取调用列表
Console.WriteLine("\n--- 委托调用列表 ---");
if (handler != null)
{
Delegate[] invocationList = handler.GetInvocationList();
Console.WriteLine($"委托链中有 {invocationList.Length} 个方法:");
for (int i = 0; i < invocationList.Length; i++)
{
var method = invocationList[i].Method;
Console.WriteLine($" {i + 1}. {method.DeclaringType?.Name}.{method.Name}");
}
}
// 多播委托的返回值(只返回最后一个方法的结果)
Console.WriteLine("\n--- 多播委托返回值 ---");
MathOperation multiMath = null;
multiMath += DelegateBasics.Add;
multiMath += DelegateBasics.Multiply;
int finalResult = multiMath(5, 3);
Console.WriteLine($"多播委托最终返回值:{finalResult}"); // 只返回最后一个方法的结果
}
}
// 委托的异常处理
public class DelegateExceptionHandling
{
public static void ThrowException(string message)
{
Console.WriteLine($"即将抛出异常:{message}");
throw new InvalidOperationException($"故意抛出的异常:{message}");
}
public static void SafeMethod(string message)
{
Console.WriteLine($"安全方法:{message}");
}
public static void DemonstrateExceptionHandling()
{
Console.WriteLine("\n=== 委托异常处理演示 ===");
MessageHandler handler = SafeMethod;
handler += ThrowException;
handler += SafeMethod; // 这个方法不会被执行,因为前面的方法抛出了异常
try
{
Console.WriteLine("调用包含异常的委托链:");
handler("测试消息");
}
catch (Exception ex)
{
Console.WriteLine($"捕获异常:{ex.Message}");
}
// 安全调用委托链中的每个方法
Console.WriteLine("\n--- 安全调用委托链 ---");
SafeInvokeAll(handler, "安全调用测试");
}
private static void SafeInvokeAll(MessageHandler handler, string message)
{
if (handler == null) return;
foreach (MessageHandler singleHandler in handler.GetInvocationList())
{
try
{
singleHandler(message);
}
catch (Exception ex)
{
Console.WriteLine($"方法 {singleHandler.Method.Name} 执行失败:{ex.Message}");
}
}
}
}
1.3 内置委托类型
// 内置委托类型使用
public class BuiltInDelegatesDemo
{
public static void DemonstrateBuiltInDelegates()
{
Console.WriteLine("\n=== 内置委托类型演示 ===");
// Action委托(无返回值)
Console.WriteLine("\n--- Action委托 ---");
Action simpleAction = () => Console.WriteLine("无参数Action");
simpleAction();
Action<string> stringAction = message => Console.WriteLine($"Action<string>: {message}");
stringAction("Hello Action");
Action<int, string> multiParamAction = (num, text) =>
Console.WriteLine($"Action<int, string>: {num} - {text}");
multiParamAction(42, "Answer");
// Func委托(有返回值)
Console.WriteLine("\n--- Func委托 ---");
Func<int> getRandomNumber = () => new Random().Next(1, 100);
Console.WriteLine($"随机数:{getRandomNumber()}");
Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine($"加法结果:{add(10, 20)}");
Func<string, int> getStringLength = str => str?.Length ?? 0;
Console.WriteLine($"字符串长度:{getStringLength("Hello World")}");
Func<int, bool> isEven = number => number % 2 == 0;
Console.WriteLine($"42是偶数:{isEven(42)}");
Console.WriteLine($"43是偶数:{isEven(43)}");
// Predicate委托(返回bool)
Console.WriteLine("\n--- Predicate委托 ---");
Predicate<int> isPositive = x => x > 0;
Predicate<string> isNotEmpty = str => !string.IsNullOrEmpty(str);
Console.WriteLine($"5是正数:{isPositive(5)}");
Console.WriteLine($"-3是正数:{isPositive(-3)}");
Console.WriteLine($"'Hello'非空:{isNotEmpty("Hello")}");
Console.WriteLine($"''非空:{isNotEmpty("")}");
// 使用内置委托进行集合操作
Console.WriteLine("\n--- 集合操作 ---");
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 使用Predicate过滤
var evenNumbers = Array.FindAll(numbers, isEven.Invoke);
Console.WriteLine($"偶数:[{string.Join(", ", evenNumbers)}]");
// 使用Func转换
var squares = Array.ConvertAll(numbers, x => x * x);
Console.WriteLine($"平方:[{string.Join(", ", squares)}]");
// 使用Action遍历
Console.WriteLine("遍历数组:");
Array.ForEach(numbers, num => Console.Write($"{num} "));
Console.WriteLine();
}
}
2. Lambda表达式和匿名方法
2.1 Lambda表达式
public class LambdaExpressionsDemo
{
public static void DemonstrateLambdaExpressions()
{
Console.WriteLine("\n=== Lambda表达式演示 ===");
// 基本Lambda表达式
Console.WriteLine("\n--- 基本Lambda表达式 ---");
// 无参数Lambda
Func<string> getCurrentTime = () => DateTime.Now.ToString("HH:mm:ss");
Console.WriteLine($"当前时间:{getCurrentTime()}");
// 单参数Lambda(可省略括号)
Func<int, int> square = x => x * x;
Console.WriteLine($"5的平方:{square(5)}");
// 多参数Lambda
Func<int, int, int> power = (baseNum, exponent) =>
{
int result = 1;
for (int i = 0; i < exponent; i++)
{
result *= baseNum;
}
return result;
};
Console.WriteLine($"2的3次方:{power(2, 3)}");
// 表达式体Lambda vs 语句体Lambda
Console.WriteLine("\n--- 表达式体 vs 语句体 ---");
// 表达式体(单行)
Func<double, double> circleArea = radius => Math.PI * radius * radius;
// 语句体(多行)
Func<double, string> circleInfo = radius =>
{
double area = Math.PI * radius * radius;
double circumference = 2 * Math.PI * radius;
return $"半径:{radius}, 面积:{area:F2}, 周长:{circumference:F2}";
};
Console.WriteLine($"圆形面积:{circleArea(5):F2}");
Console.WriteLine($"圆形信息:{circleInfo(5)}");
// Lambda表达式捕获外部变量
Console.WriteLine("\n--- 变量捕获 ---");
int multiplier = 10;
Func<int, int> multiplyByTen = x => x * multiplier;
Console.WriteLine($"5 × {multiplier} = {multiplyByTen(5)}");
multiplier = 20; // 修改外部变量
Console.WriteLine($"5 × {multiplier} = {multiplyByTen(5)}"); // Lambda会捕获最新值
// 复杂Lambda表达式
Console.WriteLine("\n--- 复杂Lambda表达式 ---");
var people = new[]
{
new { Name = "张三", Age = 25, City = "北京" },
new { Name = "李四", Age = 30, City = "上海" },
new { Name = "王五", Age = 22, City = "广州" },
new { Name = "赵六", Age = 28, City = "深圳" }
};
// 过滤
var adults = people.Where(p => p.Age >= 25).ToArray();
Console.WriteLine($"25岁及以上的人 ({adults.Length}个):");
foreach (var person in adults)
{
Console.WriteLine($" {person.Name}({person.Age}岁) - {person.City}");
}
// 排序
var sortedByAge = people.OrderBy(p => p.Age).ToArray();
Console.WriteLine($"\n按年龄排序:");
foreach (var person in sortedByAge)
{
Console.WriteLine($" {person.Name}({person.Age}岁) - {person.City}");
}
// 投影
var nameAndCity = people.Select(p => $"{p.Name} - {p.City}").ToArray();
Console.WriteLine($"\n姓名和城市:");
foreach (var info in nameAndCity)
{
Console.WriteLine($" {info}");
}
// 聚合
var averageAge = people.Average(p => p.Age);
var totalAge = people.Sum(p => p.Age);
Console.WriteLine($"\n平均年龄:{averageAge:F1}岁");
Console.WriteLine($"年龄总和:{totalAge}岁");
}
}
// 匿名方法(C# 2.0语法,现在较少使用)
public class AnonymousMethodsDemo
{
public static void DemonstrateAnonymousMethods()
{
Console.WriteLine("\n=== 匿名方法演示 ===");
// 匿名方法语法
Console.WriteLine("\n--- 匿名方法语法 ---");
// 使用delegate关键字
Func<int, int> doubleValue = delegate(int x) { return x * 2; };
Console.WriteLine($"匿名方法:5 × 2 = {doubleValue(5)}");
// 对比Lambda表达式
Func<int, int> doubleValueLambda = x => x * 2;
Console.WriteLine($"Lambda表达式:5 × 2 = {doubleValueLambda(5)}");
// 匿名方法捕获变量
Console.WriteLine("\n--- 匿名方法变量捕获 ---");
int factor = 3;
Func<int, int> multiplyByFactor = delegate(int x)
{
Console.WriteLine($"匿名方法中的factor值:{factor}");
return x * factor;
};
Console.WriteLine($"结果:{multiplyByFactor(7)}");
factor = 5;
Console.WriteLine($"修改factor后的结果:{multiplyByFactor(7)}");
}
}
2.2 高级Lambda应用
public class AdvancedLambdaDemo
{
// 函数式编程风格
public static void DemonstrateFunctionalProgramming()
{
Console.WriteLine("\n=== 函数式编程风格 ===");
// 高阶函数
Console.WriteLine("\n--- 高阶函数 ---");
// 返回函数的函数
Func<int, Func<int, int>> CreateMultiplier = factor => x => x * factor;
var multiplyBy2 = CreateMultiplier(2);
var multiplyBy5 = CreateMultiplier(5);
Console.WriteLine($"2倍函数:{multiplyBy2(10)}");
Console.WriteLine($"5倍函数:{multiplyBy5(10)}");
// 函数组合
Func<int, int> addOne = x => x + 1;
Func<int, int> multiplyByTwo = x => x * 2;
// 组合函数:先加1,再乘2
Func<int, int> addOneThenMultiplyByTwo = x => multiplyByTwo(addOne(x));
Console.WriteLine($"组合函数 (5+1)*2 = {addOneThenMultiplyByTwo(5)}");
// 通用函数组合器
Func<T, TResult> Compose<T, TMiddle, TResult>(
Func<T, TMiddle> first,
Func<TMiddle, TResult> second) => x => second(first(x));
var composedFunction = Compose(addOne, multiplyByTwo);
Console.WriteLine($"通用组合器 (7+1)*2 = {composedFunction(7)}");
// 柯里化(Currying)
Console.WriteLine("\n--- 柯里化 ---");
// 普通函数
Func<int, int, int, int> add3Numbers = (x, y, z) => x + y + z;
// 柯里化版本
Func<int, Func<int, Func<int, int>>> curriedAdd = x => y => z => x + y + z;
var add10 = curriedAdd(10);
var add10And20 = add10(20);
var result = add10And20(30);
Console.WriteLine($"柯里化结果:{result}");
Console.WriteLine($"直接调用:{curriedAdd(10)(20)(30)}");
// 偏函数应用
Console.WriteLine("\n--- 偏函数应用 ---");
Func<string, string, string, string> formatMessage =
(prefix, message, suffix) => $"{prefix}{message}{suffix}";
// 创建偏函数
Func<string, string> createWarning = message => formatMessage("[警告] ", message, " !");
Func<string, string> createError = message => formatMessage("[错误] ", message, " !!!");
Console.WriteLine(createWarning("这是一个警告"));
Console.WriteLine(createError("这是一个错误"));
}
// 递归Lambda表达式
public static void DemonstrateRecursiveLambda()
{
Console.WriteLine("\n--- 递归Lambda表达式 ---");
// 阶乘函数
Func<int, int> factorial = null;
factorial = n => n <= 1 ? 1 : n * factorial(n - 1);
Console.WriteLine($"5! = {factorial(5)}");
Console.WriteLine($"7! = {factorial(7)}");
// 斐波那契数列
Func<int, long> fibonacci = null;
fibonacci = n => n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
Console.WriteLine("斐波那契数列前10项:");
for (int i = 0; i < 10; i++)
{
Console.Write($"{fibonacci(i)} ");
}
Console.WriteLine();
// 使用记忆化优化递归
var memoizedFib = CreateMemoizedFunction(fibonacci);
var sw = System.Diagnostics.Stopwatch.StartNew();
long result1 = fibonacci(40);
sw.Stop();
Console.WriteLine($"普通递归 fibonacci(40) = {result1}, 耗时: {sw.ElapsedMilliseconds}ms");
sw.Restart();
long result2 = memoizedFib(40);
sw.Stop();
Console.WriteLine($"记忆化递归 fibonacci(40) = {result2}, 耗时: {sw.ElapsedMilliseconds}ms");
}
// 记忆化函数
private static Func<T, TResult> CreateMemoizedFunction<T, TResult>(Func<T, TResult> function)
{
var cache = new Dictionary<T, TResult>();
return input =>
{
if (cache.TryGetValue(input, out TResult cachedResult))
{
return cachedResult;
}
TResult result = function(input);
cache[input] = result;
return result;
};
}
}
3. 事件基础
3.1 事件的概念和定义
// 事件参数基类
public class EventArgs
{
public static readonly EventArgs Empty = new EventArgs();
}
// 自定义事件参数
public class TemperatureChangedEventArgs : EventArgs
{
public double OldTemperature { get; }
public double NewTemperature { get; }
public double Change => NewTemperature - OldTemperature;
public DateTime Timestamp { get; }
public TemperatureChangedEventArgs(double oldTemp, double newTemp)
{
OldTemperature = oldTemp;
NewTemperature = newTemp;
Timestamp = DateTime.Now;
}
}
public class FileProcessedEventArgs : EventArgs
{
public string FileName { get; }
public long FileSize { get; }
public bool Success { get; }
public string ErrorMessage { get; }
public TimeSpan ProcessingTime { get; }
public FileProcessedEventArgs(string fileName, long fileSize, bool success,
string errorMessage = null, TimeSpan processingTime = default)
{
FileName = fileName;
FileSize = fileSize;
Success = success;
ErrorMessage = errorMessage;
ProcessingTime = processingTime;
}
}
// 温度监控器类
public class TemperatureMonitor
{
private double temperature;
private readonly double minTemperature;
private readonly double maxTemperature;
// 事件声明
public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged;
public event EventHandler<EventArgs> OverheatingDetected;
public event EventHandler<EventArgs> FreezingDetected;
public TemperatureMonitor(double minTemp = -10, double maxTemp = 50)
{
minTemperature = minTemp;
maxTemperature = maxTemp;
temperature = 20; // 默认室温
}
public double Temperature
{
get => temperature;
set
{
if (Math.Abs(temperature - value) > 0.01) // 避免频繁触发
{
double oldTemp = temperature;
temperature = value;
// 触发温度变化事件
OnTemperatureChanged(new TemperatureChangedEventArgs(oldTemp, temperature));
// 检查异常温度
CheckTemperatureAlerts();
}
}
}
public string Status
{
get
{
if (temperature > maxTemperature) return "过热";
if (temperature < minTemperature) return "过冷";
return "正常";
}
}
// 事件触发方法(受保护的虚方法)
protected virtual void OnTemperatureChanged(TemperatureChangedEventArgs e)
{
TemperatureChanged?.Invoke(this, e);
}
protected virtual void OnOverheatingDetected()
{
OverheatingDetected?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnFreezingDetected()
{
FreezingDetected?.Invoke(this, EventArgs.Empty);
}
private void CheckTemperatureAlerts()
{
if (temperature > maxTemperature)
{
OnOverheatingDetected();
}
else if (temperature < minTemperature)
{
OnFreezingDetected();
}
}
// 模拟温度变化
public void SimulateTemperatureChange(double targetTemp, int steps = 10)
{
double step = (targetTemp - temperature) / steps;
for (int i = 0; i < steps; i++)
{
Temperature += step;
Thread.Sleep(100); // 模拟时间延迟
}
}
}
// 文件处理器类
public class FileProcessor
{
public event EventHandler<FileProcessedEventArgs> FileProcessed;
public event EventHandler<EventArgs> ProcessingStarted;
public event EventHandler<EventArgs> ProcessingCompleted;
private int processedCount = 0;
private int totalFiles = 0;
public int ProcessedCount => processedCount;
public int TotalFiles => totalFiles;
public double Progress => totalFiles > 0 ? (double)processedCount / totalFiles * 100 : 0;
public void ProcessFiles(string[] filePaths)
{
totalFiles = filePaths.Length;
processedCount = 0;
OnProcessingStarted();
foreach (string filePath in filePaths)
{
ProcessSingleFile(filePath);
}
OnProcessingCompleted();
}
private void ProcessSingleFile(string filePath)
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
bool success = false;
string errorMessage = null;
long fileSize = 0;
try
{
if (File.Exists(filePath))
{
var fileInfo = new FileInfo(filePath);
fileSize = fileInfo.Length;
// 模拟文件处理
Thread.Sleep(new Random().Next(100, 500));
// 模拟处理成功/失败
success = new Random().NextDouble() > 0.1; // 90%成功率
if (!success)
{
errorMessage = "模拟处理失败";
}
}
else
{
errorMessage = "文件不存在";
}
}
catch (Exception ex)
{
errorMessage = ex.Message;
}
finally
{
stopwatch.Stop();
processedCount++;
OnFileProcessed(new FileProcessedEventArgs(
Path.GetFileName(filePath),
fileSize,
success,
errorMessage,
stopwatch.Elapsed));
}
}
protected virtual void OnFileProcessed(FileProcessedEventArgs e)
{
FileProcessed?.Invoke(this, e);
}
protected virtual void OnProcessingStarted()
{
ProcessingStarted?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnProcessingCompleted()
{
ProcessingCompleted?.Invoke(this, EventArgs.Empty);
}
}
3.2 事件使用示例
public class EventDemo
{
public static void DemonstrateEvents()
{
Console.WriteLine("\n=== 事件演示 ===");
// 温度监控演示
Console.WriteLine("\n--- 温度监控演示 ---");
var monitor = new TemperatureMonitor(-5, 40);
// 订阅事件
monitor.TemperatureChanged += OnTemperatureChanged;
monitor.OverheatingDetected += OnOverheatingDetected;
monitor.FreezingDetected += OnFreezingDetected;
// 模拟温度变化
Console.WriteLine($"初始温度:{monitor.Temperature}°C ({monitor.Status})");
Console.WriteLine("\n模拟升温到45°C:");
monitor.SimulateTemperatureChange(45);
Console.WriteLine("\n模拟降温到-10°C:");
monitor.SimulateTemperatureChange(-10);
Console.WriteLine("\n模拟回到正常温度25°C:");
monitor.SimulateTemperatureChange(25);
// 文件处理演示
Console.WriteLine("\n--- 文件处理演示 ---");
var processor = new FileProcessor();
// 订阅事件
processor.ProcessingStarted += (sender, e) =>
Console.WriteLine("开始处理文件...");
processor.FileProcessed += OnFileProcessed;
processor.ProcessingCompleted += (sender, e) =>
{
var fp = sender as FileProcessor;
Console.WriteLine($"\n处理完成!总计:{fp.TotalFiles}个文件,成功:{fp.ProcessedCount}个");
};
// 创建一些测试文件路径
string[] testFiles = {
"test1.txt",
"test2.txt",
"test3.txt",
"nonexistent.txt",
"test4.txt"
};
processor.ProcessFiles(testFiles);
}
private static void OnTemperatureChanged(object sender, TemperatureChangedEventArgs e)
{
var monitor = sender as TemperatureMonitor;
Console.WriteLine($"温度变化:{e.OldTemperature:F1}°C → {e.NewTemperature:F1}°C " +
$"(变化:{e.Change:+0.0;-0.0}°C) [{monitor.Status}]");
}
private static void OnOverheatingDetected(object sender, EventArgs e)
{
Console.WriteLine("⚠️ 警告:检测到过热!");
}
private static void OnFreezingDetected(object sender, EventArgs e)
{
Console.WriteLine("❄️ 警告:检测到过冷!");
}
private static void OnFileProcessed(object sender, FileProcessedEventArgs e)
{
var processor = sender as FileProcessor;
string status = e.Success ? "✅" : "❌";
string sizeInfo = e.FileSize > 0 ? $" ({e.FileSize} bytes)" : "";
string errorInfo = !e.Success && !string.IsNullOrEmpty(e.ErrorMessage) ? $" - {e.ErrorMessage}" : "";
Console.WriteLine($"{status} {e.FileName}{sizeInfo} - {e.ProcessingTime.TotalMilliseconds:F0}ms" +
$"{errorInfo} [{processor.Progress:F1}%]");
}
}
4. 观察者模式实现
4.1 经典观察者模式
// 观察者接口
public interface IObserver<T>
{
void Update(T data);
}
// 主题接口
public interface ISubject<T>
{
void Attach(IObserver<T> observer);
void Detach(IObserver<T> observer);
void Notify(T data);
}
// 新闻发布者(主题)
public class NewsPublisher : ISubject<string>
{
private readonly List<IObserver<string>> observers = new List<IObserver<string>>();
private readonly List<string> news = new List<string>();
public string Name { get; }
public IReadOnlyList<string> News => news.AsReadOnly();
public NewsPublisher(string name)
{
Name = name;
}
public void Attach(IObserver<string> observer)
{
if (observer != null && !observers.Contains(observer))
{
observers.Add(observer);
Console.WriteLine($"订阅者已添加到 {Name},当前订阅者数量:{observers.Count}");
}
}
public void Detach(IObserver<string> observer)
{
if (observers.Remove(observer))
{
Console.WriteLine($"订阅者已从 {Name} 移除,当前订阅者数量:{observers.Count}");
}
}
public void Notify(string newsItem)
{
Console.WriteLine($"\n{Name} 发布新闻:{newsItem}");
foreach (var observer in observers.ToList()) // 使用ToList避免集合修改异常
{
try
{
observer.Update(newsItem);
}
catch (Exception ex)
{
Console.WriteLine($"通知观察者时发生错误:{ex.Message}");
}
}
}
public void PublishNews(string newsItem)
{
news.Add(newsItem);
Notify(newsItem);
}
public int ObserverCount => observers.Count;
}
// 新闻订阅者(观察者)
public class NewsSubscriber : IObserver<string>
{
public string Name { get; }
private readonly List<string> receivedNews = new List<string>();
public IReadOnlyList<string> ReceivedNews => receivedNews.AsReadOnly();
public NewsSubscriber(string name)
{
Name = name;
}
public void Update(string newsItem)
{
receivedNews.Add(newsItem);
Console.WriteLine($" 📰 {Name} 收到新闻:{newsItem}");
}
public void ShowReceivedNews()
{
Console.WriteLine($"\n{Name} 收到的所有新闻 ({receivedNews.Count}条):");
for (int i = 0; i < receivedNews.Count; i++)
{
Console.WriteLine($" {i + 1}. {receivedNews[i]}");
}
}
}
// 智能新闻订阅者(带过滤功能)
public class SmartNewsSubscriber : IObserver<string>
{
public string Name { get; }
private readonly List<string> keywords;
private readonly List<string> filteredNews = new List<string>();
public IReadOnlyList<string> FilteredNews => filteredNews.AsReadOnly();
public SmartNewsSubscriber(string name, params string[] keywords)
{
Name = name;
this.keywords = keywords?.ToList() ?? new List<string>();
}
public void Update(string newsItem)
{
bool isRelevant = keywords.Count == 0 ||
keywords.Any(keyword => newsItem.Contains(keyword, StringComparison.OrdinalIgnoreCase));
if (isRelevant)
{
filteredNews.Add(newsItem);
Console.WriteLine($" 🎯 {Name} 收到相关新闻:{newsItem}");
}
else
{
Console.WriteLine($" ⏭️ {Name} 过滤了新闻:{newsItem}");
}
}
public void AddKeyword(string keyword)
{
if (!string.IsNullOrEmpty(keyword) && !keywords.Contains(keyword))
{
keywords.Add(keyword);
}
}
public void RemoveKeyword(string keyword)
{
keywords.Remove(keyword);
}
public void ShowKeywords()
{
Console.WriteLine($"{Name} 的关键词:[{string.Join(", ", keywords)}]");
}
}
4.2 观察者模式演示
public class ObserverPatternDemo
{
public static void DemonstrateObserverPattern()
{
Console.WriteLine("\n=== 观察者模式演示 ===");
// 创建新闻发布者
var techNews = new NewsPublisher("科技新闻");
var sportsNews = new NewsPublisher("体育新闻");
// 创建订阅者
var generalReader = new NewsSubscriber("普通读者");
var techEnthusiast = new SmartNewsSubscriber("科技爱好者", "AI", "编程", "科技");
var sportsLover = new SmartNewsSubscriber("体育爱好者", "足球", "篮球", "比赛");
var newsCollector = new NewsSubscriber("新闻收集者");
Console.WriteLine("\n--- 订阅设置 ---");
// 订阅科技新闻
techNews.Attach(generalReader);
techNews.Attach(techEnthusiast);
techNews.Attach(newsCollector);
// 订阅体育新闻
sportsNews.Attach(generalReader);
sportsNews.Attach(sportsLover);
sportsNews.Attach(newsCollector);
// 显示关键词
techEnthusiast.ShowKeywords();
sportsLover.ShowKeywords();
Console.WriteLine("\n--- 发布新闻 ---");
// 发布科技新闻
techNews.PublishNews("AI技术在医疗领域取得重大突破");
techNews.PublishNews("新的编程语言发布,性能提升50%");
techNews.PublishNews("量子计算机研究获得新进展");
// 发布体育新闻
sportsNews.PublishNews("世界杯足球赛决赛今晚举行");
sportsNews.PublishNews("NBA篮球比赛创收视率新高");
sportsNews.PublishNews("奥运会游泳比赛打破世界纪录");
Console.WriteLine("\n--- 取消部分订阅 ---");
// 普通读者取消科技新闻订阅
techNews.Detach(generalReader);
// 继续发布新闻
techNews.PublishNews("区块链技术在金融领域的应用");
Console.WriteLine("\n--- 订阅者收到的新闻统计 ---");
generalReader.ShowReceivedNews();
Console.WriteLine($"\n科技爱好者收到的相关新闻 ({techEnthusiast.FilteredNews.Count}条):");
for (int i = 0; i < techEnthusiast.FilteredNews.Count; i++)
{
Console.WriteLine($" {i + 1}. {techEnthusiast.FilteredNews[i]}");
}
Console.WriteLine($"\n体育爱好者收到的相关新闻 ({sportsLover.FilteredNews.Count}条):");
for (int i = 0; i < sportsLover.FilteredNews.Count; i++)
{
Console.WriteLine($" {i + 1}. {sportsLover.FilteredNews[i]}");
}
newsCollector.ShowReceivedNews();
Console.WriteLine($"\n发布者统计:");
Console.WriteLine($" {techNews.Name}:{techNews.News.Count}条新闻,{techNews.ObserverCount}个订阅者");
Console.WriteLine($" {sportsNews.Name}:{sportsNews.News.Count}条新闻,{sportsNews.ObserverCount}个订阅者");
}
}
5. 总结
本章深入介绍了C#委托和事件的核心概念:
- 委托基础:委托的概念、多播委托、内置委托类型
- Lambda表达式:表达式语法、变量捕获、函数式编程
- 匿名方法:delegate语法、与Lambda的对比
- 事件机制:事件定义、事件参数、事件处理
- 观察者模式:经典实现、智能订阅、事件驱动架构
关键要点: - 委托是类型安全的函数指针 - 多播委托支持调用链 - Lambda表达式提供简洁的函数式编程语法 - 事件是特殊的委托,提供发布-订阅模式 - 观察者模式实现松耦合的对象通信 - 合理使用事件可以构建响应式系统
下一章预告: 下一章我们将学习LINQ(语言集成查询),包括查询语法、方法语法、延迟执行和自定义LINQ扩展。