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;
        }
    }
}
(0)

相关推荐

  • 一探即将到来的 C# 10

    hez2010 dotNET跨平台 今天 前言 本来因为懒不想写这篇文章,但是不少人表示有兴趣,于是最后决定还是写一下. .NET 6 最近几个预览版一直都在开发体验(如 hot reload.lin ...

  • 带你了解C#每个版本新特性

    上学时学习C#和.NET,当时网上的资源不像现在这样丰富,所以去电脑城买了张盗版的VS2005的光盘,安装时才发现是VS2003,当时有一种被坑的感觉,但也正是如此,让我有了一个完整的.NET的学习生 ...

  • 理解lambda表达式,为什么用它?

    初学者接触 lambda表达式 ,觉得语法很清奇,正好今天看到 python weekly 推送了一个youtube的视频教程,今天大邓就顺便领大家简单认识一下lambda语法. up主:PyLeni ...

  • 函数与Lambda表达式

    函数参数定义 # 学习人员:贾其豪# 开发时间:2021/1/31 14:05#函数定义默认值参数#函数定义时,给形参设置默认值,只有与默认值不符的时候才需要传递实参def fun(a,b=10): ...

  • 说说Python中的lambda表达式?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  • Java函数式编程和lambda表达式

    为什么要使用函数式编程# 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基 ...

  • 深入浅出 Java 8 Lambda 表达式

    摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...

  • C++之Lambda表达式

    C++之Lambda表达式

  • C++11初探:lambda表达式和闭包

    到了C++11最激动人心的特性了: 匿名函数:lambda表达式 假设你有一个vector<int> v, 想知道里面大于4的数有多少个.for循环谁都会写,但是STL提供了现成算法cou ...

  • lambda linq 表达式 ListBox 的升序 降序 乱序

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  • 什么是Python表达式?Python基础入门

    初学Python的时候,大家都会接触到各种专业术语,比如说表达式.语句等,那么你知道什么是Python表达式吗?Python表达式由什么构成呢?想要知道,这篇文章你一定要看. Python表达式由什么 ...