• C# Lambda Expressions 简介(转载)


    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 = 0;

                // Initialize the delegates with lambda expressions.

                // Note access to 2 outer variables.

                // del will be invoked within this method.

                del = () => { j = 10;  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 //注意jdel的执行过程中被修改

                Console.WriteLine("j = {0}. b = {1}", j, boolResult);

            }

     

            static void Main()

            {

                Test test = new Test();

                test.TestMethod(5);

     

                // Prove that del2 still has a copy of

                // local variable j from TestMethod. //j的引用超出了原先定义的作用域

                bool result = test.del2(10);

     

                // Output: True

                Console.WriteLine(result);

               

                Console.ReadKey();

            }

        }

     

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

    ·         被“捕获”的变量在委托的生命周期结束前都不会被垃圾回收;

    ·         Lambda内部定义的变量对外不可见;

    ·         Lambda无法直接捕获一个具有refout描述的参数变量;

    ·         Lambda中的return语句不会导致当前所在的方法返回;

    ·         Lambda中不允许包含会导致跳当前执行范围的gotobreak continue语句。

     

    6.  总结

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

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

    转自:http://www.cnblogs.com/smwikipedia/archive/2009/05/06/1450825.html

  • 相关阅读:
    从.Net迁移到.Net Core时,需要注意的兼容性变更
    P/Invoke各种总结(五、在C#中使用指针类型)
    P/Invoke各种总结(四、平台调用时的数据类型对应)
    解决Visual Studio 2017/2019 "const char *"类型的值不能用于初始化"char *"类型的实体的问题
    .Net Framework、.Net Core和.Net Standard的区别
    C#代码分析工具Style Cop使用
    《代码不朽:编写可维护软件的10大要则(C#版)》读书笔记
    Visual C++中宽字节与多字节字符互相转换的方法
    浮动和定位
    关于如何设置图片大小和图片形状
  • 原文地址:https://www.cnblogs.com/johnwonder/p/1957581.html
Copyright © 2020-2023  润新知