C# Lambda Expressions 简介

原文http://msdn2.microsoft.com/en-us/library/bb397687.aspx

翻译:朱之光 (larry1zhu@gmail.com)

1.  Lambda简介

一个Lambda Expression  (译为Lambda式) 就是一个包含若干表达式和语句的匿名函数。可以被用作创建委托对象或表达式树类型。

所有的Lambda式都使用操作符“=>“,表示“goes to (转变为)”。操作符左边部分是输入参数表,右边部分是表达式或语句块。x => x * x 读成“x转变为x 乘x”。

Lambda式可以被赋值给一个委托类型:

例1

delegate int del(int i);

del myDelegate = x => x * x;

int j = myDelegate(5); //j = 25

也可以被用于创建一个表达式树类型:

例2

using System.Linq.Expressions;

//…

Expression<del> = x => x *x;

操作符“=>”具有和“=”一样的运算优先级,且为右相关(右边先执行)。

在例1中,我们注意到委托的定义中有一个int类型的输入参数以及int类型的返回值。例子中的Lambda式中并没有任何类型的声明。是编译器为我们做了相应的隐式数据类型转换:输入参数类型能够从委托的输入参数类型隐式转换,返回类型能够被隐式转换为委托的返回类型。

Lambda式不允许作为“is”和“as”操作符的左操作数出现。也就是

del myDelegate = x => x * x as string;      //error

所有对于匿名方法的约束也同样适用于Lambda式。请参阅Anonymous Methods (C# Programming Guide).

2.  表达式Lambda

由一个计算表达式组成的一个Lambda式称之为表达式Lambda。表达式Lambda常被用于构造表达式树。一个表达式Lambda返回计算表达式运算的结果。

基本结构:

(input parameters) => expression

如果只有一个输入参数时,括号可以省略。如果具有一个以上的输入参数,必需加上括号。

(x) => x * x 等于 x => x * x

(x, y) => x == y

可以显式指定输入参数的类型

(int x, string s) => s.Length > x

也可以没有任何输入参数

() => SomeMethod1()

上面这段代码在Lambda式中调用了一个方法。需要注意的是,如果在创建会被其他方使用的表达式树的时候,不宜在Lambda式中执行方法调用。比如:在SQL Server内执行。

一般来说,让一个方法在原先设计的上下文环境以外执行没有意义,也不能真正工作。

3.  语句Lambda

语句Lambda和表达式Lambda非常相似,只是语句被包含在大括号内:

(input parameters) => {statement;}

大括号中的语句可以是任意多条,也可以写成多行(定义一个Lambda式也就是在定义一个匿名方法):

TestDelegate myDel = n => { string s = n + " " + "World";

Console.WriteLine(s); };

当然语句Lambda跟匿名方法一样,无法用于创建表达式树。

4.  类型猜测

当编写一个Lambda式的时候,我们通常不需要明确指定输入参数的类型。因为编译器会根据Lambda体的实现,以及委托的定义来猜测类型。

举例:如果要从一个List<int>中删除小于100的元素

lst.RemoveAll(i => i < 100);       //i会被猜测为int

通常的猜测规则如下:

  • Lambda式必须包含与委托定义中相等数量的输入参数;
  • 每个Lambda式的输入参数必须能够隐式转换成委托定义中所要求的输入参数;
  • Lambda式的返回值必须能够隐式转换成委托定义中的返回值。

注意:由于目前在common type system中还没有一个“Lambda式类型”的类型。如果在有些场合提到“Lambda式的类型”,那通常表示委托的定义或者是Expression<>类型。

5.  Lambda中的变量作用域

在Lambda式定义中可以引用外部变量。只要是在定义处能够访问到的变量,都可以在Lambda式中引用。

Lambda式的定义仅仅是定义一个匿名方法,最终会生成一个委托对象。外部变量的引用将被“捕获”到委托对象内部,将会伴随委托对象的整个生命周期。在委托对象生命周期结束之前该变量都不会被垃圾回收。就算外部变量已经超过了原来的作用域,也还能继续在Lambda式中使用。所有会被引用的外部变量必须在Lambda式定义之前被显式赋值。见下例

    delegate bool D();
delegate bool D2(int i); class Test
{
D del;
D2 del2; public void TestMethod(int input)
{
int j = ;
// Initialize the delegates with lambda expressions.
// Note access to 2 outer variables.
// del will be invoked within this method.
del = () => { j = ; return j > input; }; // del2 will be invoked after TestMethod goes out of scope.
del2 = (x) => {return x == j; }; // Demonstrate value of j:
// Output: j = 0
// The delegate has not been invoked yet.
Console.WriteLine("j = {0}", j); // Invoke the delegate.
bool boolResult = del(); // Output: j = 10 b = True
//注意j在del的执行过程中被修改
Console.WriteLine("j = {0}. b = {1}", j, boolResult);
} static void Main()
{
Test test = new Test();
test.TestMethod(); // Prove that del2 still has a copy of
// local variable j from TestMethod.
//j的引用超出了原先定义的作用域
bool result = test.del2(); // Output: True
Console.WriteLine(result);
Console.ReadKey();
}
}

作用域

下面是关于变量作用域的规则:

  • 被“捕获”的变量在委托的生命周期结束前都不会被垃圾回收;
  • 在Lambda式内部定义的变量对外不可见;
  • Lambda式无法直接捕获一个具有ref或out描述的参数变量;
  • Lambda式中的return语句不会导致当前所在的方法返回;
  • Lambda式中不允许包含会导致跳当前执行范围的goto,break 或 continue语句。

     6.  总结

Lambda式可以说就是另外一种形式的匿名方法。用在某些地方,会使代码更加简洁。

定义一个Lambda式本质上就是定义一个委托的实现体。

C# Lambda Expressions 简介的更多相关文章

  1. jdk8新特性之lambda expressions

    本文分两部分: 语法简单说明 lambda的使用 注:这两部分内容均以类+注释的方式进行说明,并且内容均来自官方教程(https://docs.oracle.com/javase/tutorial/j ...

  2. java语言中的匿名类与lambda表达式介绍与总结 (Anonymous Classes and Lambda Expressions)

    2017/6/30 转载写明出处:http://www.cnblogs.com/daren-lin/p/anonymous-classes-and-lambda-expressions-in-java ...

  3. 1.8 新特性之 Lambda Expressions

    Lambda expressions are allowed only at source level 1.8 or above The target type of this expression ...

  4. lambda expressions are not supported at this language level

    IDEA下报错:lambda expressions are not supported at this language level 解决: 1. File -> Project Struct ...

  5. ef中用lambda expressions时要注意(m=>m.id ==b ) 此时的b只能是基本的数据类型 。连属性都不能用

    ef中用lambda expressions时要注意(m=>m.id ==b ) 此时的b只能是基本的数据类型 .连属性都不能用

  6. Hacking Lambda Expressions in Java

    Hacking Lambda Expressions in Javahttps://dzone.com/articles/hacking-lambda-expressions-in-java At t ...

  7. 【104】Maven3.5.0结合eclipse使用,提示Lambda expressions are allowed only at source level 1.8 or above错误的解决方法

    错误重现 我的机器上安装了 maven 3.5.0,在 eclipse 中创建 maven 项目.pom.xml配置如下: <project xmlns="http://maven.a ...

  8. AS报错:lambda expressions are not supported at this language level

    AS报错:lambda expressions are not supported at this language level 解决方法 打开打开 File --> Project Stuct ...

  9. Lambda Expressions and Functional Interfaces: Tips and Best Practices

    转载自https://www.baeldung.com/java-8-lambda-expressions-tips 1. Overview   Now that Java 8 has reached ...

随机推荐

  1. Grunt 认识

    基本工作流: JS合并.JS压缩.CSS压缩.CSS Sprite.图片优化.测试.静态资源缓存(版本更新)... 基于工作流产生的工具: JSHint(jshint.com).CSSLint(css ...

  2. ionic2 页面加载时图片添加的问题

    使用ionic2创建项目时,在app文件夹下有图片目录img 在home中引用图片,但是不论是用ng-src或者是src,代码如下: <ion-list> <ion-slides c ...

  3. Codevs 1009 产生数

    题目描述 Description 给出一个整数 n(n<10^30) 和 k 个变换规则(k<=15). 规则: 一位数可变换成另一个一位数: 规则的右部不能为零. 例如:n=234.有规 ...

  4. 深度模拟java动态代理实现机制系类之三

    这里的内容就比较复杂了,要实现的是对任意的接口,对任意指定的方法,以及对任意指定的代理类型进行代理,就更真实的模拟出java虚拟机的动态代理机制 罗列一下这里涉及的类.接口之间的关系,方便大家学习.1 ...

  5. Lucene使用IKAnalyzer分词实例 及 IKAnalyzer扩展词库

    文章转载自:http://www.cnblogs.com/dennisit/archive/2013/04/07/3005847.html 方案一: 基于配置的词典扩充 项目结构图如下: IK分词器还 ...

  6. WPF中XAML转义字符

    字符 转义字符 备注 & (ampersand) & 这个没什么特别的,几乎所有的地方都需要使用转义字符 > (greater-than character) > 在属性( ...

  7. Java操作MongoDB

    上一篇文章: http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html 介绍到了在MongoDB的控制台完成MongoDB的数据操作,通 ...

  8. 实现Server.UrlEncode和Server.UrlDecode功能的js代码

    <script> var EncodeURI = function(unzipStr,isCusEncode){    if(isCusEncode){        var zipArr ...

  9. Ajax入门小例子

    大牛文章:http://www.cnblogs.com/guduoduo/p/3681296.html                               ---Ajax基础学习 http:/ ...

  10. WPF-数据绑定:日期时间格式

    WPF-数据绑定:日期时间格式绑定后自定义格式的例子. 我刚才遇到的问题是绑定完之后,星期始终显示为英文.需要一个属性ConverterCulture制定区域. 如下: {Binding dateti ...