跳至内容
张叶安的小站
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
csharp:第八章委托与事件
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 第八章 委托与事件 ====== ===== 8.1 委托基础 ===== === 什么是委托 === 委托(Delegate)是一种类型,它安全地封装了方法的引用。可以把委托看作是指向方法的指针,但它比C/C++的函数指针更安全、更灵活。 === 定义和使用委托 === <code csharp> // 1. 定义委托类型 public delegate void MyDelegate(string message); public delegate int CalculatorDelegate(int a, int b); // 2. 创建与委托匹配的方法 public static void ShowMessage(string msg) { Console.WriteLine($"消息: {msg}"); } public static void ShowUpperMessage(string msg) { Console.WriteLine($"消息: {msg.ToUpper()}"); } public static int Add(int a, int b) => a + b; public static int Multiply(int a, int b) => a * b; // 3. 使用委托 public class DelegateDemo { public static void Main() { // 创建委托实例 MyDelegate del = ShowMessage; del("Hello World"); // 调用 // 委托多播(组合多个方法) MyDelegate multiDel = ShowMessage; multiDel += ShowUpperMessage; multiDel("Hello"); // 两个方法都会执行 // 使用CalculatorDelegate CalculatorDelegate calc = Add; Console.WriteLine(calc(5, 3)); // 8 calc = Multiply; Console.WriteLine(calc(5, 3)); // 15 } } </code> ===== 8.2 内置委托类型 ===== === Action委托 === Action是无返回值的委托,支持0-16个参数。 <code csharp> // Action委托 Action action1 = () => Console.WriteLine("无参数"); Action<string> action2 = msg => Console.WriteLine(msg); Action<int, int> action3 = (a, b) => Console.WriteLine(a + b); action1(); action2("Hello"); action3(5, 3); </code> === Func委托 === Func是有返回值的委托,最后一个类型参数是返回值类型。 <code csharp> // Func委托 Func<int> func1 = () => 42; Func<int, int, int> func2 = (a, b) => a + b; Func<string, bool> func3 = str => str.Length > 5; Console.WriteLine(func1()); // 42 Console.WriteLine(func2(5, 3)); // 8 Console.WriteLine(func3("Hello World")); // True </code> === Predicate委托 === Predicate<T>是返回bool的特定委托。 <code csharp> // Predicate委托 Predicate<int> isEven = n => n % 2 == 0; Predicate<string> isLong = str => str.Length > 10; Console.WriteLine(isEven(4)); // True Console.WriteLine(isLong("Hi")); // False </code> ===== 8.3 匿名方法与Lambda表达式 ===== === 匿名方法 === <code csharp> // 传统委托 MyDelegate del1 = ShowMessage; // 匿名方法(C# 2.0) MyDelegate del2 = delegate(string msg) { Console.WriteLine($"匿名方法: {msg}"); }; // 使用 Action<int> printSquare = delegate(int n) { Console.WriteLine(n * n); }; printSquare(5); // 25 </code> === Lambda表达式 === <code csharp> // 表达式Lambda Func<int, int> square = x => x * x; Func<int, int, int> add = (a, b) => a + b; // 语句Lambda Action<string> greet = name => { Console.WriteLine($"Hello, {name}!"); Console.WriteLine("Welcome!"); }; // 多参数 Func<int, int, int, int> sum = (a, b, c) => a + b + c; // 无参数 Action sayHello = () => Console.WriteLine("Hello!"); // 使用 Console.WriteLine(square(5)); // 25 Console.WriteLine(add(3, 4)); // 7 greet("Alice"); </code> ===== 8.4 委托的高级特性 ===== === 委托多播 === <code csharp> public class MulticastDemo { public static void Method1() => Console.WriteLine("方法1"); public static void Method2() => Console.WriteLine("方法2"); public static void Method3() => Console.WriteLine("方法3"); public static void Main() { Action multi = Method1; multi += Method2; multi += Method3; Console.WriteLine("=== 执行所有方法 ==="); multi(); Console.WriteLine("\n=== 移除方法2 ==="); multi -= Method2; multi(); // 获取调用列表 foreach (Delegate d in multi.GetInvocationList()) { Console.WriteLine($"方法: {d.Method.Name}"); } } } </code> === 泛型委托 === <code csharp> // 自定义泛型委托 public delegate TResult MyFunc<in T, out TResult>(T arg); public class GenericDelegateDemo { public static void Main() { // 使用自定义泛型委托 MyFunc<int, string> intToString = n => $"数字: {n}"; Console.WriteLine(intToString(42)); // 使用内置泛型委托 Func<string, int> stringLength = s => s.Length; Console.WriteLine(stringLength("Hello")); } } </code> ===== 8.5 事件 ===== === 事件基础 === 事件是基于委托的一种特殊机制,用于实现发布-订阅模式。 <code csharp> // 定义事件参数 public class OrderEventArgs : EventArgs { public string OrderId { get; set; } public decimal Amount { get; set; } public DateTime OrderTime { get; set; } } // 发布者 public class OrderProcessor { // 声明事件 public event EventHandler<OrderEventArgs> OrderPlaced; public event EventHandler OrderCompleted; public void PlaceOrder(string orderId, decimal amount) { Console.WriteLine($"处理订单: {orderId}"); // 触发事件 OrderPlaced?.Invoke(this, new OrderEventArgs { OrderId = orderId, Amount = amount, OrderTime = DateTime.Now }); // 处理订单... Thread.Sleep(1000); // 触发完成事件 OrderCompleted?.Invoke(this, EventArgs.Empty); } } // 订阅者 public class EmailNotifier { public void Subscribe(OrderProcessor processor) { processor.OrderPlaced += OnOrderPlaced; } private void OnOrderPlaced(object sender, OrderEventArgs e) { Console.WriteLine($"[邮件通知] 订单 {e.OrderId} 已下单,金额: {e.Amount:C}"); } } public class SmsNotifier { public void Subscribe(OrderProcessor processor) { processor.OrderPlaced += (sender, e) => { Console.WriteLine($"[短信通知] 订单 {e.OrderId} 通知已发送"); }; } } // 使用 var processor = new OrderProcessor(); var emailNotifier = new EmailNotifier(); var smsNotifier = new SmsNotifier(); emailNotifier.Subscribe(processor); smsNotifier.Subscribe(processor); processor.PlaceOrder("ORD-001", 199.99m); </code> ===== 8.6 标准事件模式 ===== === EventHandler<T>模式 === <code csharp> public class Stock { public string Symbol { get; } private decimal price; public Stock(string symbol, decimal price) { Symbol = symbol; this.price = price; } public decimal Price { get => price; set { if (price == value) return; decimal oldPrice = price; price = value; // 触发价格变化事件 OnPriceChanged(new PriceChangedEventArgs(oldPrice, price)); } } // 事件声明 public event EventHandler<PriceChangedEventArgs> PriceChanged; // 触发事件的受保护虚方法 protected virtual void OnPriceChanged(PriceChangedEventArgs e) { PriceChanged?.Invoke(this, e); } } // 事件参数 public class PriceChangedEventArgs : EventArgs { public decimal OldPrice { get; } public decimal NewPrice { get; } public decimal ChangePercent => (NewPrice - OldPrice) / OldPrice * 100; public PriceChangedEventArgs(decimal oldPrice, decimal newPrice) { OldPrice = oldPrice; NewPrice = newPrice; } } // 使用 var stock = new Stock("MSFT", 150.00m); stock.PriceChanged += (sender, e) => { Console.WriteLine($"股票价格变化: {e.OldPrice:C} -> {e.NewPrice:C} ({e.ChangePercent:F2}%)"); }; stock.Price = 155.00m; stock.Price = 160.00m; </code> ===== 8.7 实战:事件驱动架构 ===== <code csharp> // 温度监控示例 public class TemperatureSensor { private Random random = new Random(); private double currentTemperature; public double CurrentTemperature => currentTemperature; public event EventHandler<TemperatureEventArgs> TemperatureChanged; public event EventHandler<TemperatureEventArgs> TemperatureTooHigh; public event EventHandler<TemperatureEventArgs> TemperatureTooLow; public void SimulateReading() { // 模拟温度读数(20-40度之间随机) double newTemp = 20 + random.NextDouble() * 20; UpdateTemperature(newTemp); } public void SetTemperature(double temperature) { UpdateTemperature(temperature); } private void UpdateTemperature(double newTemp) { double oldTemp = currentTemperature; currentTemperature = newTemp; var args = new TemperatureEventArgs(oldTemp, newTemp); // 触发温度变化事件 TemperatureChanged?.Invoke(this, args); // 检查阈值 if (newTemp > 35) { TemperatureTooHigh?.Invoke(this, args); } else if (newTemp < 22) { TemperatureTooLow?.Invoke(this, args); } } } public class TemperatureEventArgs : EventArgs { public double OldTemperature { get; } public double NewTemperature { get; } public double Change => NewTemperature - OldTemperature; public DateTime Timestamp { get; } public TemperatureEventArgs(double oldTemp, double newTemp) { OldTemperature = oldTemp; NewTemperature = newTemp; Timestamp = DateTime.Now; } } // 不同的监听器 public class TemperatureLogger { private List<string> logs = new List<string>(); public void Subscribe(TemperatureSensor sensor) { sensor.TemperatureChanged += OnTemperatureChanged; } private void OnTemperatureChanged(object sender, TemperatureEventArgs e) { string log = $"[{e.Timestamp:HH:mm:ss}] 温度: {e.OldTemperature:F1}°C -> {e.NewTemperature:F1}°C"; logs.Add(log); Console.WriteLine($"[日志] {log}"); } public void SaveToFile(string filename) { File.WriteAllLines(filename, logs); } } public class TemperatureAlert { public void Subscribe(TemperatureSensor sensor) { sensor.TemperatureTooHigh += (s, e) => { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"⚠️ 高温警告: {e.NewTemperature:F1}°C 超过安全阈值!"); Console.ResetColor(); }; sensor.TemperatureTooLow += (s, e) => { Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine($"❄️ 低温警告: {e.NewTemperature:F1}°C 低于设定阈值!"); Console.ResetColor(); }; } } public class TemperatureDisplay { public void Subscribe(TemperatureSensor sensor) { sensor.TemperatureChanged += (s, e) => { Console.WriteLine($"📊 当前温度: {e.NewTemperature:F1}°C"); }; } } // 使用 public class TemperatureDemo { public static void Main() { var sensor = new TemperatureSensor(); var logger = new TemperatureLogger(); var alert = new TemperatureAlert(); var display = new TemperatureDisplay(); logger.Subscribe(sensor); alert.Subscribe(sensor); display.Subscribe(sensor); Console.WriteLine("=== 模拟温度监控 ==="); for (int i = 0; i < 10; i++) { sensor.SimulateReading(); Thread.Sleep(500); } // 触发高温 Console.WriteLine("\n=== 测试高温警报 ==="); sensor.SetTemperature(38); // 触发低温 Console.WriteLine("\n=== 测试低温警报 ==="); sensor.SetTemperature(18); } } </code> ===== 8.8 事件最佳实践 ===== === 线程安全的事件触发 === <code csharp> public class ThreadSafePublisher { private EventHandler<MyEventArgs> myEvent; private readonly object eventLock = new object(); public event EventHandler<MyEventArgs> MyEvent { add { lock (eventLock) { myEvent += value; } } remove { lock (eventLock) { myEvent -= value; } } } protected virtual void OnMyEvent(MyEventArgs e) { EventHandler<MyEventArgs> handler; lock (eventLock) { handler = myEvent; } handler?.Invoke(this, e); } } </code> ===== 练习题 ===== === 基础练习 === 1. **委托基础**:创建以下委托和使用: - 一个无返回值、带string参数的委托 - 一个返回int、带两个int参数的委托 - 分别使用命名方法和Lambda表达式实例化 2. **多播委托**:创建一个多播委托,依次执行以下操作: - 输出当前时间 - 输出"任务开始" - 输出"任务完成" - 然后移除"任务开始",再次执行 3. **简单事件**:创建Button类,包含Click事件。创建多个按钮,为每个按钮添加不同的点击处理程序。 === 进阶练习 === 4. **文件监视器**:创建FileWatcher类: - FileCreated事件 - FileDeleted事件 - FileChanged事件 - 模拟文件系统操作并触发相应事件 5. **进度报告系统**:创建FileDownloader类: - DownloadProgressChanged事件(报告进度百分比) - DownloadCompleted事件 - DownloadFailed事件 - 模拟下载过程并触发事件 6. **事件链**:创建Workflow类,实现步骤链: - StepStarted事件 - StepCompleted事件 - StepFailed事件 - 支持步骤重试机制 === 挑战练习 === 7. **消息总线**:实现一个简单的消息总线: - 支持发布/订阅模式 - 支持消息过滤 - 支持同步和异步处理 - 消息队列和持久化 8. **反应式编程**:使用委托和事件实现简单的反应式系统: - Observable和Observer模式 - 支持操作符(Where、Select、Merge等) - 支持冷/热Observable ===== 本章小结 ===== 本章学习了C#的委托与事件: - 委托的定义、实例化和调用 - 内置委托类型(Action、Func、Predicate) - 匿名方法与Lambda表达式 - 委托的多播特性 - 事件的声明、订阅和触发 - 标准事件模式 - 事件驱动架构实战 委托和事件是实现松耦合、可扩展架构的重要工具。
csharp/第八章委托与事件.txt
· 最后更改:
2026/02/03 19:45
由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部