C# 10 Lambda 语法的改进
C# 10 包括了对 Lambda 表达式的处理方式的许多改进:
- Lambda 表达式可以具有自然类型,这使编译器可从 Lambda 表达式或方法组推断委托类型。
- 如果编译器无法推断返回类型,Lambda 表达式可以声明该类型。
- 属性可应用于 Lambda 表达式。
这些功能使 Lambda 表达式更类似于方法和本地函数。 在不声明委托类型的变量的情况下,这些改进使得人们可以更容易使用 Lambda 表达式,并且它们可以与新的 ASP.NET Core 最小 API 更无缝地工作。
首先要介绍的是自动推断委派类型(inferred delegate type)。示例:
Func<string> hello = () => "Hello World";
Console.WriteLine(hello());
此示例在C# 9可以通过编译。到了C# 10,则因为编译器能够自动推断委派类型而可以使用var
定义委派。
var hello = () => "Hello World"; // C# 9 无法编译!
但如果委派的回传值为null,编译器则无法判定你想回传什么类型,例如:
var hello = () => null; // 无法编译!
此时如果还是想用var来声明返回类型,则可以在撰写lambda表达式的时候定义返回类型
var hello = string? () => null; // OK!
当你的程序有很复杂的嵌套lambda语句,便可使用这种明确声明返回类型的方式来减轻编译器推断类型的负担,从而加快编译速度。这是lambda语法的第二项改进。
第三项改进是当我们把lambda表达式传入某方法的参数时,参数类型可以是object
、Delegate
、Expression
M1(() => "test"); // Func<string>
M2(() => "test"); // Func<string>
M3(() => "test"); // Expression<Func<string>>
void M1(object x) { }
void M2(Delegate x) { }
void M3(Expression x) { }
在C# 9中,第1行至第3行都无法通过编译(无法将lambda表达式转换成目标参数类型),C# 10则没有问题。
最后一项改进是,lambda表达式从现在开始可以套用特征项(attribute),包括匿名方法、方法参数、以及返回值,皆可套用。示例:
var fn1 = [Description("Hello")] () => "Hello";
var fn2 = ([Description("参数") string s) => "Hello " + s;
var fn3 = [Description("Hello")]
[return: Description("返回字符串")]
([Description("参数")] string s) => "Hello " + s;
说明:
- 为
fn1
的匿名方法应用DescriptionAttribute修饰符,也就是给方法加上说明文字。 - 为
fn2
的匿名方法加上参数的说明文字。 - 为
fn3
的匿名方法、参数、返回类型都加上说明文字。
使用时机:某些API会去判断传入的委托方法是否应用了某些特性而有不同的行为,此时便可使用C# 10新增的lambda特性语法来撰写匿名方法,而不用像以前那样非得撰写具名方法不可。