C# (lambda表达式)

Posted by moloach on 2017-08-02

lambda表达式

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

通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数。

一般用于编写LINQ查询表达式

将表达式分配给委托类型

1
2
3
4
5
delegate int del(int i);
static void Main(){
del myDelegate = x => x * x;
int j = myDelegate(5);//j=25
}

创建表达式目录树类型

1
2
3
4
5
6
7
8
9
using System.Linq.Expressions'

namespace ConsoleApplication1{
class Program{
static void Main(string[] args){
Expression<del> myET = x => x*x;
}
}
}

=> 运算符

=> 标记称作 lambda 运算符。 该标记在 Lambda 表达式中用来将左侧的输入变量与右侧的 lambda 体分离。

Lambda 表达式是类似于匿名方法的内联表达式,但更加灵活;在以方法语法表示的 LINQ 查询中广泛使用了 Lambda 表达式。

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

表达式lambda

1
2
3
4
5
6
7
8
9
10
11
基本形式
(input-paramters) => expression

(x, y) => x == y

只有一个参数时,括号是可选的,否则必须加上

(int x ,string s) => s.Length > x

零个参数
() => SomeMethod()

语句lambda

语句 lambda 与表达式 lambda 表达式类似,只是语句括在大括号中:

1
2
3
4
5
6
7
8
9
(input-parameters) => { statement; }


delegate void TestDelegate(string s);

TestDelegate del = n => {
string s = n + "World";
//...
}

异步lambda

通过使用 async 和 await 关键字,你可以轻松创建包含异步处理的 lambda 表达式和语句。

例如,下面的 Windows 窗体示例包含一个调用和等待异步方法 ExampleMethodAsync的事件处理程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public partial class Form1 : Form  
{
public Form1()
{
InitializeComponent();
}

private async void button1_Click(object sender, EventArgs e)
{
// ExampleMethodAsync returns a Task.
await ExampleMethodAsync();
textBox1.Text += "\r\nControl returned to Click event handler.\n";
}

async Task ExampleMethodAsync()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay(1000);
}
}

//更改之后
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
// ExampleMethodAsync returns a Task.
await ExampleMethodAsync();
textBox1.Text += "\nControl returned to Click event handler.\n";
};
}

async Task ExampleMethodAsync()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay(1000);
}
}

带有标准查询运算符的lambda

许多标准查询运算符都具有输入参数,其类型是泛型委托系列 Func<T,TResult> 中的一种。 这些委托使用类型参数来定义输入参数的数量和类型,以及委托的返回类型。

Func 委托对于封装用户定义的表达式非常有用,这些表达式将应用于一组源数据中的每个元素。

1
2
3
4
5
6
7
8
9
10
11
public delegate TResult Func<TArg0, TResult>(TArg0, arg0)

Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); // returns false of course


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

var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);

lambda中的类型推理

在编写 lambda 时,通常不必为输入参数指定类型,因为编译器可以根据 lambda 主体、参数的委托类型以及 C# 语言规范中描述的其他因素来推断类型。 对于大多数标准查询运算符,第一个输入是源序列中的元素类型。

lambda 的一般规则

  • Lambda 包含的参数数量必须与委托类型包含的参数数量相同。
  • Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数。
  • Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型。
    1
    customers.Where(c => c.City == "London");