委托(Delegate)是一种类型,它安全地封装了方法的引用。可以把委托看作是指向方法的指针,但它比C/C++的函数指针更安全、更灵活。
// 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 } }
Action是无返回值的委托,支持0-16个参数。
// 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);
Func是有返回值的委托,最后一个类型参数是返回值类型。
// 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
Predicate<T>是返回bool的特定委托。
// 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
// 传统委托 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
// 表达式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");
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}"); } } }
// 自定义泛型委托 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")); } }
事件是基于委托的一种特殊机制,用于实现发布-订阅模式。
// 定义事件参数 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);
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;
// 温度监控示例 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); } }
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); } }
1. 委托基础:创建以下委托和使用:
2. 多播委托:创建一个多播委托,依次执行以下操作:
3. 简单事件:创建Button类,包含Click事件。创建多个按钮,为每个按钮添加不同的点击处理程序。
4. 文件监视器:创建FileWatcher类:
5. 进度报告系统:创建FileDownloader类:
6. 事件链:创建Workflow类,实现步骤链:
7. 消息总线:实现一个简单的消息总线:
8. 反应式编程:使用委托和事件实现简单的反应式系统:
本章学习了C#的委托与事件:
委托和事件是实现松耦合、可扩展架构的重要工具。