当前位置: 首页 > news >正文

C#委托、事件和lambda表达式

委托

委托就像是方法的类型,有了委托就可以把方法当参数传来传去,或者在一个变量里随时换掉要执行的方法。

// 1. 声明一个委托类型(定义:我能代表哪种方法) public delegate void MyDelegate(string msg); // 2. 写一个符合签名的方法 public static void ShowMessage(string text) { Console.WriteLine($"消息:{text}"); } // 3. 使用 MyDelegate del = ShowMessage; // 把方法赋值给委托变量 del("Hello"); // 调用委托,相当于调用 ShowMessage

大多数情况下不需要自己声明委托,直接用系统自带的就行。

// Action 示例(无返回值) Action<string> print = s => Console.WriteLine(s); print("直接用 Action"); // Func 示例(有返回值) Func<int, int, int> add = (a, b) => a + b; int result = add(3, 4); // 7

委托可以串联多个方法,调用一次就会按顺序执行全部,也就是多播。

Action act = MethodA; act += MethodB; act += MethodC; act(); // 依次执行 A、B、C // 移除方法 act -= MethodB;

事件

事件就是加了限制的委托,比如只能从外部“订阅”和“取消订阅”,不能直接触发或覆盖。相当于给委托封装了一下。

下面举个例子:

// 定义一个事件发布者 public class Button { // 事件:外部可以订阅,但不能随意触发 public event EventHandler? Clicked; // 模拟点击按钮 public void Click() { Console.WriteLine("按钮被点击了"); // 触发事件(只能在类内部触发) Clicked?.Invoke(this, EventArgs.Empty); } } // 使用 class Program { static void Main() { Button btn = new Button(); // 订阅事件(用 +=) btn.Clicked += OnButtonClicked; // 触发点击 btn.Click(); // 取消订阅(用 -=) btn.Clicked -= OnButtonClicked; // btn.Clicked.Invoke(null, null); ❌ 编译错误,外部不能触发 // btn.Clicked = null; ❌ 编译错误,外部不能赋值 } static void OnButtonClicked(object? sender, EventArgs e) { Console.WriteLine("事件处理:按钮被点击了!"); } }

输出是:

按钮被点击了 事件处理:按钮被点击了!

在.NET中推荐是使用EventHandler和EventHandler<T>,它有两个参数:

public event EventHandler<CustomEventArgs>? DataReceived;

标准写法是:

public class DataProcessor { // 声明事件(使用标准 EventHandler<T>) public event EventHandler<ProcessCompletedEventArgs>? ProcessCompleted; public void StartProcess() { // 模拟处理 Console.WriteLine("处理中..."); Thread.Sleep(1000); // 处理完成,触发事件 OnProcessCompleted(10); // 假设处理了10条数据 } // 受保护的触发方法(约定:On + 事件名) protected virtual void OnProcessCompleted(int count) { ProcessCompleted?.Invoke(this, new ProcessCompletedEventArgs(count)); } } // 自定义事件参数类 public class ProcessCompletedEventArgs : EventArgs { public int RecordCount { get; } public ProcessCompletedEventArgs(int count) => RecordCount = count; } // 使用 class Program { static void Main() { var processor = new DataProcessor(); processor.ProcessCompleted += (sender, e) => { Console.WriteLine($"处理完成!共 {e.RecordCount} 条数据"); }; processor.StartProcess(); } }

Lambda表达式

lambda表达式就是匿名方法的简写,是C#中最常用最实用的特性之一。

传统写法:

// 定义方法 bool IsEven(int x) { return x % 2 == 0; } // 使用 List<int> numbers = new List<int>{1,2,3,4,5}; var evens = numbers.Where(IsEven);

lambda写法:

var evens = numbers.Where(x => x % 2 == 0);

最直观的看到lambda写法少写了三行代码,显著减少了代码冗余。

lambda可以捕获外部变量,也就是闭包:

int multiplier = 3; Func<int, int> multiply = x => x * multiplier; // 捕获了 multiplier int result = multiply(5); // 15 multiplier = 10; result = multiply(5); // 50(外部变量变化,Lambda 也跟着变)

但在循环中捕获变量时,很容易造成“延迟执行”的问题。

var actions = new List<Action>(); for (int i = 0; i < 3; i++) { actions.Add(() => Console.WriteLine(i)); // 捕获同一个 i } foreach (var action in actions) { action(); // 输出 3, 3, 3 而不是 0,1,2 }

解决方法也很简单,就是在循环内局部复制一份:

for (int i = 0; i < 3; i++) { int copy = i; // 每次循环新建一个变量 actions.Add(() => Console.WriteLine(copy)); } // 输出 0,1,2

一般情况下,编译器会根据上下文推断lambda的类型,只有上下文不够明确时,才需要显示声明类型:

// ❌ 错误:无法推断 var lambda = x => x * 2; // ✅ 正确:明确委托类型 Func<int, int> lambda = x => x * 2;
http://www.cnnetsun.cn/news/3593734.html

相关文章:

  • 真激动,千问新人优惠券大放送!激活码:千问新人福利yPBm3m
  • 如果f(3x+2)是奇函数,求f(x)的对称中心
  • ESP32网络电台DIY:低成本构建物联网音频系统
  • 2026年AI大模型岗位趋势与核心技术解析
  • Loop Engineering 学习笔记:从手写 Prompt 到设计循环
  • 多语言句子嵌入与可靠性审计:技术原理与部署实践
  • 深入解析TI MibSPI并行模式与多缓冲机制:高速嵌入式通信实战
  • 从双雄到三强:Kimi K3暂停注册、DeepSeek V4满血回归,中国AI正在改写全球游戏规则
  • Qwen 3.8大模型本地部署与交互应用开发实战指南
  • 【深度】别再神话 Skill 了——一个完整 Skill 到底由什么组成,为什么多数 Skill 跑不起来
  • RAG Chunk 策略怎么定?固定长度 vs 语义分块 vs Agent 分块
  • P1025 数的划分 题解复盘
  • AI生成文本检测技术解析:从特征识别到学术诚信实践
  • Claude Code离线安装方案揭秘:从零搭建企业级AI编程助手环境
  • Linux服务器WebDriver启动Chrome浏览器失败排查指南
  • 51单片机烧烤机设计(附代码与仿真)
  • MHmarkets:聚焦细节,看看风控思路的关键框架
  • ChatGPT宕机启示:构建抗脆弱工作流与容灾策略
  • 中国制造开源AI权重模型:从技术突破到工程实践
  • 纠缠几何:统一量子电路切割、经典难度与可训练性的新框架
  • AI换脸工具,2026年换脸工作流,5款实测解析
  • RTX 3080部署70亿参数大语言模型:本地量化推理实战指南
  • 企业API限流困境与多Key架构解决方案
  • 国产AI大模型本地化部署指南:月之暗面联合阿里模型实战测试
  • 欧易OKX年夜饭活动:高端服务与科技细节解析
  • Unity后处理堆栈Volume系统:从原理到实战,掌握效果混合与动态控制
  • Linux 效率神器:fc 命令详解 —— 快速编辑 重执行历史命令
  • 实时推荐转化率提升37.6%的关键:动态会话建模与冷启动融合策略,仅限头部平台内部流出
  • FPG财盛国际:围绕外汇行业合规表达与移动端体验的清单评估
  • FPG财盛国际:围绕外汇市场服务体验与用户体验路径的逻辑复盘