什么是 Lambda表达式?
- Lambda表达式其实就是一个用来代替委托实例的未命名的方法;
- 编译器会把 Lambda表达式转化为以下二者之一:
- 一个委托实例。
- 一个表达式树,他表示了可遍历的对象模型中 Lambda表达式里面的代码。它允许 Lambda表达式延迟到运行时再被解释。
例子:
- 每个Lambda表达式的参数对应委托的参数
- 表达式的类型对应委托的返回值类型
delegate int Transformer(int i);
//委托变量 = 方法的参数 => 方法的返回值
//x对应于声明委托中参数i ; x*x对应声明委托中int型返回值
Transformer sqr = x => x*x;
Console.Write(sqr(3)); //输出9
Lambda表达式的代码也可以是语句块:x => {return x*x;};
实际上,编译器会通过编写一个私有方法来解析这个 Lambda表达式,然后把表达式的代码移动到这个方法里。
Lambda表达式的形式
- (parameters)=> expression Or statement-block
- (参数) => 表达式或语句块
其中如果只有一种参数并且类型可推断的话,那么参数的小括号可以省略
Func & Action
Lambda表达式通常与Func和Action委托一起使用
Func<int,int> sqr = x => x*x ;
Func<string,string,int> totalLength = (s1,s2) => s1.Length + s2.Length ;
int total = totalLength("hello","world"); //total is 10
显式指定Lambda表达式的参数类型
void Foo<T>(T x){}
void Bar<T>(Action<T> a){}
Bar(x => Foo(x)); //What type is x?
三种解决办法:
Bar((int)x) => Foo(x)); //参数加上类型
Bar<int>(x => Foo(x)); //指定泛型类型参数的类型
Bar<int>(Foo); //方法组
Lambda表达式捕获外部变量
Lambda表达式可以引用本地的变量和所在方法得参数
static void Main()
{
int factor = 2;
Func<int,int> mul = n => n*factor;
Console.WriteLine(mul(3)); //6
}
- 被Lambda表达式易用的外部变量叫做被捕获的变量;
- 捕获了外部变量的Lambda表达式叫做闭包;
- 被捕获的外部变量是在委托被实际调用的时候才被计算,而不是在捕获的时候。
int factor = 2;
Func<int,int> mul = n => n*factor;
factor = 10;
Console.WriteLine(mul(3)); //30
Lambda表达式本身也可以更新被捕获的变量
int seed = 0;
Func<int> nal = () => seed++ ;
Console.WriteLine(nal ()); //0
Console.WriteLine(nal ()); //1
Console.WriteLine(seed); //2
- 被捕获的变量生命周期会被延长到和委托一样
- 在Lambda表达式内实例化的本地变量对于委托实例的每次调用来说都是唯一的
- 当捕获for循环的迭代变量时,c#会把这个变量当作是一个在循环外部定义的变量,这就意味着每次迭代捕获的都是同一个变量。
为什么输出“333”原理如下:
如何解决?
Lambda表达式 vs 本地方法
本地方法更好一些
- 可以简单明了的进行递归
- 无需指定委托类型
- 性能开销略低一点(他避开了委托的间接调用)