C# lambda表达式 匿名函数

匿名函数

C# 中的匿名函数是一种没有名称的函数,通常用于创建简短的委托或表达式树。它们在 C# 2.0 版本中引入,并且随着语言的发展,匿名函数的使用变得更加广泛和强大。

匿名函数的基本语法:

delegateName = (parameterList) => expression;

delegateName 是委托的名称。
parameterList 是函数参数的列表。
expression 是匿名函数体,它是一个表达式,返回一个值。

示例:

// 一个简单的匿名函数,计算两个数的和
Func<int, int, int> add = (x, y) => x + y;

// 调用匿名函数
int result = add(5, 10);
Console.WriteLine(result); // 输出 15

匿名函数的几种形式:

不带参数的匿名函数:

Action action = () => Console.WriteLine("Hello, World!");
action();

带单个参数的匿名函数:

Func<int, int> square = x => x * x;

带多个参数的匿名函数:

Func<int, int, int> sum = (x, y) => x + y;

使用外部变量的匿名函数:

int multiplier = 2;
Func<int, int> multiply = x => x * multiplier;

匿名方法(C# 2.0 风格):

delegate void MyDelegate(string message);
MyDelegate del = delegate(string message) { Console.WriteLine(message); };
del("Hello from an anonymous method!");

Lambda 表达式:

Lambda 表达式是匿名函数的一种简写形式,通常用于委托和表达式树。

Func<int, int> square = x => x * x;

总结

匿名函数在 C# 中非常有用,特别是在需要快速定义一个小型函数,而不需要完整方法定义的情况下。它们在 LINQ 查询、事件处理、异步编程等场景中非常常见。


lambda表达式

C# 中的 lambda 表达式是一种简洁的表示匿名函数的方法。Lambda 表达式特别用于 LINQ 查询、事件处理程序、回调函数等场景中,它使得代码更加简洁和易于阅读。

Lambda 表达式的基本语法如下:

(input-parameters) => expression-or-statement-block

这里 input-parameterslambda 表达式的参数列表,它可以包含零个、一个或多个参数。=>lambda 运算符,它分隔参数列表和表达式或语句块。expression-or-statement-blocklambda 主体,可以是单个表达式或语句块。

下面是一些 lambda 表达式的例子:

无参数 lambda 表达式:

() => Console.WriteLine("Hello, World!")

单个参数 lambda 表达式:

x => x * x // 这是一个简单的平方计算 lambda

多个参数 lambda 表达式:

(x, y) => x + y // 这是一个简单的加法计算 lambda

带有语句块的 lambda 表达式:

(x, y) => {  
    int sum = x + y;  
    return sum * sum; // 返回两数之和的平方  
}

在实际使用中,lambda 表达式经常与委托或 FuncAction泛型委托结合使用。例如:

Func<int, int, int> add = (x, y) => x + y;  
int result = add(5, 3); // result 将会是 8

在这个例子中,我们定义了一个名为 addFunc<int, int, int> 类型的委托,它接受两个 int 类型的参数并返回一个 int 类型的值。Lambda 表达式 (x, y) => x + y 被赋值给这个委托,然后我们可以像调用普通方法一样调用这个委托。

Lambda 表达式在 LINQ 查询中也非常有用,例如:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };  
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();
// 筛选偶数

在这个 LINQ 查询中,n => n % 2 == 0 是一个 lambda 表达式,它定义了筛选偶数的条件。

关于参数

C#中,当使用lambda表达式时,参数的类型确实可以省略,这是因为在大多数情况下,编译器可以根据lambda表达式使用的上下文(比如它赋值给的委托类型或者它所在的方法签名)来推断出参数的类型。这称为类型推断

例如,如果你有一个接受Func<int, int, bool>委托的方法,你可以这样传递一个lambda表达式,而不需要显式指定参数类型:

Func<int, int, bool> isDivisible = (a, b) => a % b == 0;

在这个例子中,编译器可以推断出ab都是int类型,因为Func<int, int, bool>委托期望两个int类型的参数和一个bool类型的返回值。

然而,在某些情况下,你可能需要显式指定参数类型,特别是当lambda表达式没有直接赋值给委托或者当上下文不足以让编译器进行类型推断时。在这些情况下,你可以像下面这样显式指定参数类型:

(int a, int b) => a % b == 0

显式指定类型可以提供更好的代码可读性,特别是在复杂的lambda表达式或者当参数类型不是显而易见的时候。不过,在大多数简单场景中,省略类型并使用类型推断可以使代码更简洁。

总的来说,是否需要在lambda表达式中指定参数类型取决于具体的使用场景和上下文。在能够利用类型推断的情况下,通常可以省略类型以简化代码。

表达式或语句块

C#中,lambda表达式的返回行为取决于它的使用上下文。如果lambda表达式被赋值给一个返回类型的委托(比如Func系列委托),或者它用于表达式树中且需要返回一个值,那么lambda表达式必须包含返回语句(return),除非它的主体本身就是一个表达式(在这种情况下,表达式的值就是lambda的返回值)。

如果lambda表达式赋值给的是一个没有返回值的委托(比如Action系列委托),或者它是事件处理器等不需要返回值的场景,那么它不应该包含return语句。在这些情况下,lambda表达式的主体通常是一个语句块,执行一系列操作但不返回任何值。

以下是一些例子来说明这些概念:

有返回值的lambda表达式(使用return):

Func<int, int, bool> isDivisible = (a, b) => {  
    return a % b == 0; // 使用return语句返回bool值  
};

或者,如果lambda的主体只是一个表达式,你可以省略大括号和return语句:

Func<int, int, bool> isDivisible = (a, b) => a % b == 0; 
// 表达式的结果就是返回值

没有返回值的lambda表达式(不使用return):

Action<string> printMessage = message => {  
    Console.WriteLine(message); // 执行操作,不返回任何值  
};

在这个例子中,printMessage是一个Action<string>类型的委托,它接受一个字符串参数并执行一个操作(打印消息到控制台),但不返回任何值。因此,lambda表达式的主体是一个语句块,它包含了一系列操作语句,而不是一个返回语句。

总结来说,是否需要在lambda表达式中使用return语句取决于该lambda表达式所代表的函数的预期行为:是否需要返回一个值。如果需要返回值,则必须使用return语句(除非lambda的主体本身就是一个表达式);如果不需要返回值,则不应该使用return语句。

一个神奇的例子与总结

class TODO {
    public static void Main(String[] args) {
        Func<int, int ,double >rule = (x, y) => {
            return x + y;
        };

        Console.WriteLine(rule(1, 2));

    }
}

/*
var rule = new Func<int, int, double>((x, y) => {
    return x + y;
});
*/

C#中,你提供的两个代码片段定义了一个接受两个int类型参数并返回一个double类型结果的Func委托。虽然这两个代码片段在功能上完全相同,但它们在语法和可读性方面有一些细微的差别。

第一个代码片段

Func<int, int, double> rule = (x, y) => {  
    return x + y;  
};

在这个片段中,rule是一个Func<int, int, double>类型的变量,它直接通过lambda表达式进行初始化。这种语法在C#中非常常见,因为它简洁且直接。这里,lambda表达式(x, y) => { return x + y; }定义了委托的行为。

第二个代码片段

var rule = new Func<int, int, double>((x, y) => {  
    return x + y;  
});

注意其中的varFunc<int, int, double>

在这个片段中,rule同样是一个Func<int, int, double>类型的变量,但它是通过new关键字和Func的构造函数来初始化的。虽然这种语法是完全有效的,但它通常不如第一个片段那样常见或推荐,因为它稍微冗长一些。不过,这种语法在某些情况下可能更清晰,尤其是当需要在初始化委托的同时进行其他操作时。

区别总结
语法简洁性:第一个代码片段更简洁,因为它直接通过lambda表达式进行初始化,而不需要使用new关键字和构造函数。

可读性:对于大多数C#开发者来说,第一个代码片段可能更易于阅读和理解,因为它直接反映了委托的类型和它的行为。

性能:在实际运行时,这两种语法在性能上是没有区别的。它们都会创建一个新的委托实例,并将lambda表达式编译成的方法作为该委托的调用目标。

灵活性:虽然第一个代码片段更常见,但第二个代码片段在某些特定场景下可能更有用,尤其是当需要更复杂的初始化逻辑时。

在实际编程中,建议使用第一个代码片段的语法,因为它更简洁、更常见,也更容易被其他开发者理解。

换句话说

C#中,当你使用lambda表达式来创建委托的实例时,你实际上是在隐式地创建一个匿名函数并将其赋值给委托变量。在这个过程中,你不需要显式地使用new关键字来创建委托的实例,因为编译器会自动为你处理这些细节。

例如,下面的代码展示了如何使用lambda表达式来隐式地创建一个Func<int, int, bool>类型的委托实例:

Func<int, int, bool> isDivisible = (x, y) => x % y == 0;

在这个例子中,我们没有使用new关键字来创建Func<int, int, bool>的实例。相反,我们直接将lambda表达式(x, y) => x % y == 0赋值给了isDivisible变量。编译器会自动处理lambda表达式的编译和委托实例的创建。

然而,如果你想要显式地通过委托的构造函数来创建一个委托实例,那么你需要使用new关键字,就像这样:

Func<int, int, bool> isDivisible = new Func<int, int, bool>((x, y) => x % y == 0);

虽然这种语法是有效的,但它通常是不必要的,并且会使代码看起来更加冗长。直接使用lambda表达式来赋值给委托变量是更常见和推荐的做法。

总之,当你使用lambda表达式来创建委托实例时,你不需要显式地使用new关键字。编译器会自动为你处理这些细节,使代码更加简洁和易读。

  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值