[C# Essentials] Delegate and Lambda Expression

Tags

Delegate

 
 
notion image

Statement Lambda

替代简单委托实例的一种方法
(paras…) => {block with return statement}
在类型很显然的情况,不需要显式说明参数类型:
public static void BubbleSort(int[] items, Func<int, int, bool> compare) { // ... } // call BubbleSort(items, (first, second) => { return first < second; })
 

Expression Lambda

(paras) => expression
注意事项:
  • Lambda表达式本身没有类型,不能访问其任何成员(包括object的方法)
  • 不能在内部用跳转语句跳转到外部
  • 编译器确定性赋值分析机制在Lambda表达式内部检测不到对外部局部变量进行初始化的情况
    • 比如在lambda表达式内部对一个未初始化的变量赋值,此时编译器仍认为这个变量是未初始化的
 
 

Anonymous Method

C#2.0之前不支持Lambda表达式,只引入了Lambda表达式
BubbleSort(items, delegate(int first, int second) { return first < second; })
无参匿名方法:省去整个函数参数列表,兼容任何返回某类型的委托
古老写法,不常用
delegate {return Console.ReadLine() != "";}
 
 

委托的逆变和协变

参数向下兼容(子 = 父),返回值向上(父 = 子)
Func<object, string?> func1 = (object data) => data.ToString(); Func<string, object?> func2 = func1;
 

外部变量

被lambda表达式捕捉的外部变量生存期会被延长
避免在lambda表达式中捕捉循环变量
 

Lambda和匿名函数的内部机制

编译器会将这俩转换为特殊的隐藏类、字段和方法
没有外部变量就直接生成静态方法,有则会生成一个sealed class(或者说,闭包)
class DelegateSample { // 这是lambda表达式在CIL中生成的闭包 private sealed class _LocalsDisplayClass_00000001 { public int comparisonCount; public bool _AnonymousMethod_0000000(int first, int second) { comparisonCount++; return first < second; } } // ... static void Main(string[] args) { _LocalsDisplayClass_00000001 locals = new _LocalsDisplayClass_00000001(); locals.comparisonCount = 0; int[] items = new int[5]; /* 原代码: BubbleSort(items, (first, second) => { comparisonCount++; return first < second }) */ BubbleSort(items, locals._AnonymousMethod_0000000); Console.WriteLine("Items were compared {0} times.", locals.comparisonCount); } }
 

表达式树