C#中的Lambda表达式是一种简洁的匿名函数表示方式,它基于委托体系发展而来,能够让代码编写更加简洁灵活,在实际开发中广泛应用于集合操作、事件处理等场景。

委托的基础概念
委托是C#中用于封装方法的类型,它定义了方法签名,允许将方法作为参数传递或者赋值给委托变量。在Lambda表达式出现之前,委托是处理回调、事件等场景的核心方式。
比如定义一个简单的委托类型,用来封装无参数无返回值的方法:
// 定义委托类型
public delegate void MyDelegate();
class Program
{
static void Main()
{
// 实例化委托,绑定普通方法
MyDelegate del = new MyDelegate(PrintHello);
del();
}
static void PrintHello()
{
Console.WriteLine("Hello World");
}
}
匿名方法的过渡
每次使用委托都需要先定义对应的方法,代码会显得比较冗余。C# 2.0引入了匿名方法,允许直接在委托赋值时编写方法体,不需要单独定义方法名。
用匿名方法改写上面的委托使用示例:
public delegate void MyDelegate();
class Program
{
static void Main()
{
// 使用匿名方法给委托赋值
MyDelegate del = delegate()
{
Console.WriteLine("Hello World");
};
del();
}
}
匿名方法减少了额外方法定义的工作量,但是语法上还是有一些冗余,比如delegate关键字和参数括号的存在。
Lambda表达式的基本语法
C# 3.0引入了Lambda表达式,它是对匿名方法的进一步简化,语法更加简洁。Lambda表达式的基本结构是参数列表 => 方法体,其中=>被称为Lambda运算符。
上面的示例用Lambda表达式改写后如下:
public delegate void MyDelegate();
class Program
{
static void Main()
{
// 使用Lambda表达式给委托赋值
MyDelegate del = () =>
{
Console.WriteLine("Hello World");
};
del();
}
}
如果方法体只有一行代码,还可以省略大括号和分号,进一步简化:
public delegate void MyDelegate();
class Program
{
static void Main()
{
MyDelegate del = () => Console.WriteLine("Hello World");
del();
}
}
带参数的Lambda表达式
如果委托有参数,Lambda表达式的参数列表需要和委托的签名匹配:
// 定义带参数的委托
public delegate int CalculateDelegate(int a, int b);
class Program
{
static void Main()
{
// 带参数的Lambda表达式
CalculateDelegate add = (x, y) => x + y;
int result = add(3, 5);
Console.WriteLine(result); // 输出8
}
}
Lambda表达式与内置委托类型
实际开发中不需要每次都自定义委托类型,C#已经内置了常用的泛型委托类型Func和Action,可以覆盖绝大多数场景。
Action:封装无返回值的方法,支持最多16个输入参数Func:封装有返回值的方法,最后一个泛型参数是返回值类型,支持最多16个输入参数
使用内置委托类型改写上面的计算示例:
class Program
{
static void Main()
{
// Func<int, int, int> 表示输入两个int参数,返回int结果
Func<int, int, int> add = (x, y) => x + y;
int result = add(3, 5);
Console.WriteLine(result); // 输出8
// Action<string> 表示输入一个string参数,无返回值
Action<string> print = s => Console.WriteLine(s);
print("Test Message");
}
}
Lambda表达式的高级用法
闭包特性
Lambda表达式可以捕获外层作用域的变量,这个特性被称为闭包。被捕获的变量的生命周期会延长到和委托对象一致。
class Program
{
static void Main()
{
int baseNum = 10;
// Lambda表达式捕获了外层的baseNum变量
Func<int, int> addBase = x => x + baseNum;
Console.WriteLine(addBase(5)); // 输出15
baseNum = 20;
Console.WriteLine(addBase(5)); // 输出25,说明捕获的是变量引用不是值
}
}
在集合操作中使用Lambda
Lambda表达式在LINQ操作中非常常用,比如对集合进行筛选、排序、映射等操作。
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 筛选出偶数
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();
foreach (var num in evenNumbers)
{
Console.WriteLine(num); // 输出2、4、6
}
// 对每个元素乘2
var doubledNumbers = numbers.Select(n => n * 2).ToList();
foreach (var num in doubledNumbers)
{
Console.WriteLine(num); // 输出2、4、6、8、10、12
}
}
}
作为事件处理程序
Lambda表达式也可以直接作为事件的处理程序,简化事件绑定的代码。
using System;
using System.Timers;
class Program
{
static void Main()
{
Timer timer = new Timer(1000);
// 用Lambda表达式作为Elapsed事件的处理程序
timer.Elapsed += (sender, e) => Console.WriteLine($"定时器触发,时间:{e.SignalTime}");
timer.Start();
Console.ReadLine();
}
}
注意事项
- Lambda表达式如果捕获了迭代变量,在循环中使用时需要注意变量捕获的时机,避免预期外的结果
- 过长的Lambda表达式会降低代码可读性,如果逻辑复杂建议单独定义方法
- Lambda表达式可以作为表达式树的一部分,用于动态构建查询逻辑,这是更高级的应用场景