zoukankan      html  css  js  c++  java
  • Lambda表达式

    记录 Lambda

    两种显示形式:

    // 第一种:表达式Lambda,右边主体为表达式。
    (parameters) => expression
    // 第二种:语句Lambda,右边主体为语句块。
    (parameters) => { < sequence - of - statements > }

    “=>”Lambda声明运算符,左边是lambda参数,右边是lambda主体,这三个元素构成了Lambda表达式。

    所有Lambda表达式都能转换成委托。如果Lambda表达式没有返回值,则可以转成Action委托类型之一。

    // Action有16种重载
    Action action = () => Console.Write("");
    Action<int, int> action1 = (x, y) => Console.WriteLine(x*y);
    Action<string, string, int> action2 = (x, y, z) => Console.Write(x);
    Action<string, string, int,long> action3 = (x, y, z,m) => Console.Write(x);

    如果Lambda表达式有返回值,则可以转成Func委托类型之一。

    // Func有17种重载
    Func<int> func = () => 9;
    Func<int, string> func1 = x => x.ToString();
    Func<int, string> func2 = (x) => x.ToString();
    Func<int, int,string> func3 = (x,y) => (x+y).ToString();
    Func<int, int,string> func4 = (x,y) => { return (x + y).ToString(); };

    使用表达式作为主体的“表达式Lambda”可以转换为表达式树,语句Lambda则不可以转换为表达式树。

    System.Linq.Expressions.Expression<Func<int, int>> e = x => x * x;
    System.Linq.Expressions.Expression<Action> e1 = () => Console.WriteLine("");

    在需要用到委托类型或表达式的实例时,都可以使用 Lambda表达式。

    // 泛型参数类型是Func<T,TResult>,根据表达式推理,则参数类型是Func<int,int>
    var squaredNumbers = numbers.Select(x=>x*x);
    // Action参数
    Task.Run(() => { });

    参数个数为0,必须有括号。

    Func<int> func = () => 9;
    

     参数个数为1,有无括号都可。

    Func<int, string> func1 = x => x.ToString();
    Func<int, string> func2 = (x) => x.ToString();
    

     参数个数超1,必须有括号。

    Action<string, string, int> action2 = (x, y, z) => Console.Write(x);
    

    语句Lambda的主体可以包含任意数量的语句,通常不超过3句

    Action<string> greet = name =>
    {
        string greeting = $"Hello {name}!";
        Console.WriteLine(greeting);
    };
    
    // 不太好看
    Action<string> greet1 = name =>
    {
        string greeting = $"Hello {name}!";
        Console.WriteLine(greeting);
        Console.WriteLine(greeting);
        Console.WriteLine(greeting);
    };

    异步的Lambda表达式,async放在参数前。

    public Form1()
    {
        button1.Click += async (sender, e) => await ExampleMethodAsync();
    
        Action<string> action = async name => { await ExampleMethodAsync(); };
        Action<string> action1 = async (name) => { await ExampleMethodAsync(); };
    }
    
    private async Task ExampleMethodAsync()
    {
        await Task.Delay(1000);
    }

    元组类型参与的Lambda表达式(元组字段可以取别名)

     Func<(int, int, int), (int, int, int)> doubleThem = ns => (2 * ns.Item1, 2 * ns.Item2, 2 * ns.Item3);
     var numbers = (2, 3, 4);
     var doubledNumbers = doubleThem(numbers);
     Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");
    
     Func<(int n1, int n2, int n3), (int a, int b, int c)> func = ns => (8 * ns.n1, 8 * ns.n2, 8 * ns.n3);
     var numbers1 = (5, 6, 7);
     var result = func(numbers1);
     var a = result.a;
     var b = result.b;
     var c = result.c;

    编译器可以推导输入参数类型,但可以显示指定类型。

    int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int oddNumbers = numbers.Count((int n)=>n%2==1);

    Lambda类型推理

    lambda参数个数与委托类型输入参数个数要一致;Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型;

    Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数(举例不成功,气死我了)

    // 两个输入参数,Lambda包含的参数个数推理出两个,且类型为int
    Func<int, int, int> func = (x, y) => x * y;
    // 推理出的参数个数不对,编译报错
    Func<int, int, int> func1 = (x, y, z) => x * y;
    // 结果类型可以隐式转换成long
    Func<int, int, long> func2 = (x, y) => x * y;
    // 结果类型不能从int隐式转换为string,编译报错
    Func<int, int, string> func3 = (x, y) => x * y;

    Lambda外部变量和变量范围

    Lambda捕获的外部变量是否被回收,取决于引用变量的委托是否被回收。(下面代码的updateCapturedLocalVariable被回收,j变量就会被回收)。

    Lambda引入的变量,外部无法访问。(下面的temp变量)

    Lambda无法捕获in、out、ref参数。(下面的input如果用ref修饰,则lambda编译报错)

    Lambda里的goto、break、continue只能在本主体起作用,外面不能跳进来,里面不能跳出去

    using System;
    
    namespace ConsoleApp4
    {
        class Program
        {
            public static void Main()
            {
                var game = new VariableCaptureGame();
                game.Run(90);
                // j=99
                game.updateCapturedLocalVariable(9);
    
                // True,依旧可以访问j变量
                Console.WriteLine(game.isEqualToCapturedLocalVariable(99));
                // False,依旧可以访问j变量
                Console.WriteLine(game.isEqualToCapturedLocalVariable(87));
            }
        }
    
        public class VariableCaptureGame
        {
            internal Action<int> updateCapturedLocalVariable;
            internal Func<int, bool> isEqualToCapturedLocalVariable;
    
            public void Run(int input)
            {
                int j = 0;
    
                updateCapturedLocalVariable = x =>
                {
                    j = x + input;
              // 此变量temp,外面不能访问
              var temp = 9; }; isEqualToCapturedLocalVariable
    = p => p == j; } } }
  • 相关阅读:
    SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition
    SpringBoot 系列教程 JPA 错误姿势之环境配置问题
    react中constructor()和super()的具体含义以及如何使用
    原生js之canvas时钟组件
    js求和运算在可变参数的情况下ES3、ES5和ES6的写法区别
    好用的jquery.animateNumber.js数字动画插件
    sublime text3中设置Emmet输入标签自动闭合
    原生js移动端列表无缝间歇向上滚动
    原生js实现preAll和nextAll方法
    基于SwiperJs的H5/移动端下拉刷新上拉加载更多
  • 原文地址:https://www.cnblogs.com/bibi-feiniaoyuan/p/lambda.html
Copyright © 2011-2022 走看看