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表达式(一)

  • 相关阅读:
    623. Add One Row to Tree 将一行添加到树中
    771. Jewels and Stones 珠宝和石头
    216. Combination Sum III 组合总数三
    384. Shuffle an Array 随机播放一个数组
    382. Linked List Random Node 链接列表随机节点
    向github项目push代码后,Jenkins实现其自动构建
    centos下安装Jenkins
    python提取批量文件内的指定内容
    批处理实现:批量为文件添加注释
    python抓取每期双色球中奖号码,用于分析
  • 原文地址:https://www.cnblogs.com/peterYong/p/10138075.html
Copyright © 2011-2022 走看看