zoukankan      html  css  js  c++  java
  • C# Lambda

    介绍  

    Lambda 表达式是一种可用于创建 委托 或 表达式目录树 类型的 匿名函数 ,但是比匿名函数更简洁。

    通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数。 Lambda 表达式对于编写 LINQ 查询表达式特别有用。

    Lambda表达式本身可划分为两种类型:语句Lambda和表达式Lambda

    若要创建 Lambda 表达式,需要在 Lambda 运算符 => (goes to)左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块。

    格式

    (input parameters) => expression

    或者 

    (input parameters) => {statement;}

    左边参数列表可以有多个参数,一个参数,或者无参数;参数类型可以隐式或者显式,参数类型可以忽略,因为可以根据使用的上下文进行推断而得到。

    仅当 lambda 只有一个输入参数时,括号才是可选的;否则括号是必需的。

    例如:
                    (x, y) => x * y                              //多参数,隐式类型=> 表达式
                    x => x * 10                                  //单参数,隐式类型=>表达式
                    x => { return x * 10; }                   //单参数,隐式类型=>语句块
                    (int x) => x * 10                            //单参数,显式类型=>表达式
                    (int x) => { return x * 10; }            //单参数,显式类型=>语句块
                    () => Console.WriteLine()                //无参数

    例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值。 

    Lambda表达式与委托类型

    如下面的示例所示,你可以将此表达式分配给委托类型:

    delegate int del(int i); 
    static void Main(string[] args) 
    { 
        del myDelegate = x => x * x; 
        int j = myDelegate(5); //j = 25 
    }

    => 运算符具有与赋值运算符 (=) 相同的优先级并且是右结合运算

    使用 Lambda 表达式创建该委托最为方便

     Lambda表达式可以被转成委托类型,但必须满足以下几点: 
            1.两者参数个数相同 
            2.参数类型相同,注意隐式类型要参与类型辨析 
            3.委托的返回类型要与Lambda的相同,不论是表达式还是语句块

    Lambda与匿名函数的对比:

    public delegate int DelegateTest(int n1, int n2);
            static void Main(string[] args)
            {
                //委托:方法作为参数传递
                var r1 = Result(3, 4, Sum);  
                //使用匿名方法传递委托
                var r4 = Result(3,4,delegate(int x,int y){return x+y;});
                //语句lambda传递委托
                var r2 = Result(3, 4, (a, b) => { return a - b; }); 
                //lambda传递委托
                var r3 = Result(3, 4, (a, b) => a * b); 
                Console.ReadLine();
            }
            public static int Result(int a, int b, DelegateTest @delegate)
            {
                return @delegate(a, b);
            }
            public static int Sum(int a, int b)
            {
                return a + b;
            }
    View Code

    Func和Lambda

    更加简化了代码量,此时就不用像上面一样就行声明委托直接可以用

    public static void LambdaFunc()
            {
                Func<string, string, string> getFunc = (p1, p2) =>
                {
                    return p1 + "    " + p2;
                };
              Console.WriteLine(getFunc("我是第一个参数","我是第二个参数"));
            }

    Linq和Lambda

       //获取所有的用户ID

                List<string> gidList = Users.Select(p => p.Gid).ToList();

               //获取所有大于6的集合

                aaList = retList.Where(p => p > 6).ToList();

    异步 lambda

    通过使用 async 和 await 关键字,你可以轻松创建包含异步处理的 lambda 表达式和语句。 例如,下面的 Windows 窗体示例包含一个调用和等待异步方法 ExampleMethodAsync的事件处理程序。

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            button1.Click += async (sender, e) =>
            {
                await ExampleMethodAsync();
                textBox1.Text += "
    Control returned to Click event handler.
    ";
            };
        }
    
        private async Task ExampleMethodAsync()
        {
            // The following line simulates a task-returning asynchronous process.
            await Task.Delay(1000);
        }
    }
    View Code

    Lambda表达式的内部机制

    Lambda表达式并非CLR内部的固有构造,它们的实现是由C#编译器在编译时生成的。Lambda表达式为“以内嵌方式声明委托”模式提供一个对应的C#与语言构造。所以,当我们编写lambda时,编译器实际上会生成一系列代码,就以上面的代码为例,通过反编译工具查看生成的等价代码:

    Main方法中使用lambda表达式传递委托,编译后生成的是匿名函数。这也证明了上面说的lambda其实就是简化了的匿名函数

    再来看看上面的匿名方法 delegate(int x,int y){return x+y;}和lambad表达式(a, b) => { return a - b; }、(a, b) => a * b),编译后实际生成了3个静态方法 <Main>b_0,<Main>b_1和<Main>b_2,也就是说,在调用的时候还是由这3个静态方法去分别实例化成委托,并作为参数传递的,又回到了最初对委托的了解:委托实现把方法作为参数传入到另一个方法

    表达式树

    表达式树是一种允许将lambda表达式表示为树状数据结构而不是可执行逻辑的代码。

    表达式树的创建:

    1.通过Lambda表达式创建表达式树

     下面的代码演示将lambda表达式表示为可执行代码和表达式树:

       Func<int, int> res = x => x + 1;               //Code 
       Expression<Func<int, int>> exp = x => x + 1;   //Data

    进行上面的赋值之后,委托res引用返回x+1的方法,表达式树exp引用描述表达式x=>x+1的数据结构,这是两者的明显区别。

    2.通过API创建表达式树

        要使用API创建表达式树,需要使用Expression类。该类提供创建特定类型的表达式树节点的静态方法,例如:ParameterExpression(表示一个变量或参数)或MethodCallExpression(表示一个方法调用)。下面演示使用API创建一个表达式树:

    static void Main(string[] args)
            {//创建表达式树:Expression<Func<int, int>> exp = x => x + 1;
                ParameterExpression param = Expression.Parameter(typeof(int),"x");
                ConstantExpression value = Expression.Constant(1, typeof(int));
                BinaryExpression body = Expression.Add(param, value);
                Expression<Func<int, int>> lambdatree = Expression.Lambda<Func<int, int>>(body, param);
                Console.WriteLine("参数param:{0}", param);
                Console.WriteLine("描述body:{0}", body);
                Console.WriteLine("表达式树:{0}", lambdatree);
    
                //解析表达式树:
                //取得表达式树的参数
                ParameterExpression dparam = lambdatree.Parameters[0] as ParameterExpression;
                //取得表达式树描述
                BinaryExpression dbody = lambdatree.Body as BinaryExpression;
                //取得节点
                ParameterExpression left = dbody.Left as ParameterExpression;
                ConstantExpression right = body.Right as ConstantExpression;
                Console.WriteLine("解析出的表达式:{0}=>{1} {2} {3}", param.Name, left.Name, body.NodeType, right.Value);
                Console.ReadLine();
            }
    View Code

    运行结果:

    关于表达式树:表达式树这一概念的引入,使得程序可以将一个lambda表达式编译成数据来表示,而不是编译成一个表示为委托的具体实现(静态方法)。利用这一特性,Linq to Sql和Linq to Xml等库能解释表达式树,并在CIL之外的上下文中使用。

    更多参考:

    Lambda 表达式(C# 编程指南)

    C#之Lambda不得不说的用法

    Lambda表达式和表达式树

    快乐的Lambda表达式(一)

  • 相关阅读:
    面向接口编程详解(二)——编程实例
    面向接口编程详解(一)——思想基础
    设计模式之面向接口编程
    EF数据注解
    很多人不知道可以使用这种 key 的方式来对 Vue 组件时行重新渲染
    这是最新的一波Vue实战技巧,不用则已,一用惊人
    Node.js 进阶-你应该知道的 npm 知识都在这
    Vue响应式原理
    eslint规则
    简述vue-cli中chainWebpack的使用方法
  • 原文地址:https://www.cnblogs.com/peterYong/p/10138075.html
Copyright © 2011-2022 走看看