1. 核心关系图示
A[委托] --> B[提供方法容器]
B --> C[Lambda表达式]
C --> D[委托实例的语法糖]
A --> E[类型安全约束]
C --> F[编译器自动生成委托实例]
2. 本质联系
2.1 类型关系
- Lambda表达式 是编译器生成的委托实例
- 表达式自动匹配符合签名的委托类型
cs
// 等效代码对比
Func<int, int> square = x => x * x;
// 编译器生成:
Func<int, int> square = delegate(int x) { return x * x; };
2.2 编译机制
cs
var list = new List<int> { 1, 2, 3 }; var evens = list.Where(n => n % 2 == 0);
// 编译器处理为:
IEnumerable<int> evens = Enumerable.Where(list, new Func<int, bool>(匿名方法对象));
3. 关键交互特性
3.1 类型推断
cs
// 明确委托类型时
Action<string> logger = msg => Console.WriteLine(msg);
// 需显式声明类型的情况
var processor = new SomeProcessor();
processor.DoWork((int x, int y) => x + y);
// 无法推断参数类型时
3.2 闭包现象
void CreateActions(List<Action> actions)
{
for (int i = 0; i < 3; i++)
{
actions.Add(() => Console.WriteLine(i));
}
}
// 输出全为3(闭包捕获变量引用)
4. 应用场景对比
4.1 传统委托 vs Lambda
场景 | 传统委托写法 | Lambda写法 |
---|---|---|
按钮点击事件 | button.Click += delegate { ... } |
button.Click += (s,e) => {...} |
LINQ筛选 | Where(delegate(int x) { return x>5; }) |
Where(x => x > 5) |
异步回调 | Task.Run(delegate { ... }) |
Task.Run(() => { ... }) |
4.2 特殊交互案例
cs
// 多播委托中的Lambda
Action multiAction = () => Console.Write("A");
multiAction += () => Console.Write("B");
multiAction();
// 输出AB(保留执行顺序)
// 带返回值的Lambda
Func<int> counter = () => {
int count = 0; return ++count;
};
Console.WriteLine(counter());
// 每次输出1(状态不保留)
5. 底层原理分析
5.1 编译结果对比
cs
// 源代码
Func<int, bool> isEven = n => n % 2 == 0;
// 反编译结果(部分)
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Func<int, bool> <>9__0_0;
internal bool <Main>b__0_0(int n)
{ return n % 2 == 0; } }
// 实际调用
Func<int, bool> isEven = <>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Func<int, bool>(<>c.<>9.<Main>b__0_0));
5.2 内存模型
A[Lambda表达式] --> B[编译器生成密封类]
B --> C[捕获的变量变为类的字段]
B --> D[委托实例指向类方法]
6. 最佳实践
6.1 选择依据
情况 | 推荐方式 |
---|---|
简单单行逻辑 | Lambda表达式 |
需要重用方法体 | 具名方法+委托 |
需要维护复杂状态 | 类实例方法 |
6.2 性能提示
cs
// 避免高频调用的Lambda(每次生成新委托)
for (int i = 0; i < 100000; i++)
{ var temp = i; Task.Run(() => Process(temp));
// 产生大量临时委托 }
// 优化方案(预先生成委托)
static readonly Action<int> ProcessAction = Process;
static void Process(int num)
{
/*...*/
}
// 调用
Task.Run(() => ProcessAction(i));
7. 常见误区
7.1 延迟执行陷阱
var values = new[] { 1, 2, 3 };
var filters = new List<Func<int, bool>>();
for (int i = 0; i < 3; i++)
{ filters.Add(x => x > i);
// 捕获变化的i }
// 实际执行时i=3,所有条件变为x>3 Console.WriteLine(filters(2));
// 输出False
7.2 空值判断问题
EventHandler handler = null;
handler += (s, e) => Console.Write("A");
// 实际是handler = lambda handler?.Invoke(); // 可正常执行