C#类成员赋值时匿名delegate与lambda表达式的差异问题
C# 匿名方法与Lambda表达式的参数匹配差异说明
你观察到的编译差异,本质是C# 2.0引入的**匿名方法(anonymous method,即直接用delegate关键字编写的内联委托)**和C# 3.0引入的Lambda表达式,存在明确的语法规则区别,二者并非完全等价的语法糖。
三种写法的编译逻辑解释
- 官方文档给出的写法
这是合法的匿名方法写法。匿名方法独有的规则是:当你不需要在方法体内使用委托的入参时,可以完全省略参数列表,编译器会自动按照目标委托的签名完成参数绑定,不管委托定义了多少个、什么类型的入参,都不会触发签名不匹配错误。Action<DateTime> _dateSelectedHandler = delegate { }; - 第一次改写的无参Lambda
编译报错是Lambda的严格参数匹配规则导致的:Lambda的参数列表必须和目标委托的签名完全对应——写Action<DateTime> _dateSelectedHandler = () => { };()就显式声明了这个匿名函数接收0个入参,和Action<DateTime>要求的1个DateTime类型入参完全不匹配,自然无法通过编译。
IDE把匿名方法的delegate关键字悬停提示为“Lambda expression”属于提示文本的泛化简化,它把所有内联编写的匿名函数都归到了Lambda的分类下,不代表二者语法规则一致。 - 第二次改写的带参Lambda
这个写法合法,是因为显式声明了1个入参,参数数量和目标委托匹配,编译器可以根据Action<DateTime> _dateSelectedHandler = (aux) => { };Action<DateTime>的泛型定义自动推导aux的类型为DateTime,符合Lambda的类型推导规则。
匿名方法的不可替代性说明
匿名方法没有被Lambda完全替代,核心原因就是它独有的「省略参数列表自动适配签名」的特性,在不需要使用委托入参的场景下可以大幅简化代码:
比如在Xamarin、WinForm等UI框架中注册事件时,绝大多数场景下根本不会用到事件约定的sender和事件参数对象:
// 匿名方法写法:不需要声明两个完全用不到的参数 submitButton.Click += delegate { ShowToast("提交成功"); }; // Lambda写法:必须显式写全两个参数,哪怕完全不使用 submitButton.Click += (sender, e) => { ShowToast("提交成功"); };
除此之外,匿名方法还支持在省略参数列表时,自动为带返回值的委托返回类型默认值,这个特性Lambda也不具备。
注:C# 9.0之后Lambda引入了弃元参数简化,可以用
_代表不需要使用的参数,比如上面的事件可以写成(_, _) => { ... },Action<DateTime>场景可以写成(_) => { },但依然要求显式写出和委托参数数量一致的占位符,做不到匿名方法那样完全省略参数列表。
内容的提问来源于stack exchange,提问作者Josip Juros
相关产品推荐
相关产品推荐

