C# 函数式编程:从入门到精通
函数式编程(FP)是一种将计算视为数学函数求值,并避免可变状态和副作用的编程范式。尽管 C# 是一种多范式语言,对面向对象编程(OOP)有强大支持,但其现代版本(从 C# 3.0 开始)积极融入了函数式风格的元素。这使得编写更简洁、可预测且易于测试的代码成为可能。
在本文中,我们将从基础到高级技术,在 .NET 环境下探索 C# 中的函数式编程。您将学习如何使用 lambda 表达式、LINQ、不可变数据类型和模式来构建可靠的应用程序。
1. 基础:Lambda 表达式与委托
C# 中函数式方法的核心是 lambda 表达式——可用于创建委托或表达式树的匿名函数。它们允许将行为作为数据进行传递。
考虑一个经典的列表排序示例。我们不再创建单独的比较方法,而是使用 lambda:
using System;using System.Collections.Generic;
public class LambdaExample{ public static void Main() { var numbers = new List<int> { 5, 3, 8, 1, 9 }; // 使用 lambda 表达式进行降序排序 numbers.Sort((x, y) => y.CompareTo(x)); Console.WriteLine(string.Join(", ", numbers)); // 输出:9, 8, 5, 3, 1 }}这里涉及的关键概念:
- 委托
Func<>和Action<>:Func<T, TResult>返回值,Action<T>不返回值。Lambda 可隐式转换为这些类型。 - 闭包(Closures):Lambda 可以捕获外部作用域中的变量,这使其成为强大的工具,但由于可能的副作用需要谨慎使用。
2. LINQ:声明式数据处理风格
语言集成查询(LINQ)可以说是 C# 中函数式编程最突出的应用。它允许使用方法链对集合、数据库和 XML 编写声明式查询。
我们不再使用命令式的 foreach 循环,而是使用函数式操作:
using System;using System.Linq;using System.Collections.Generic;
public class LinqExample{ public static void Main() { var people = new List<Person> { new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 17 }, new Person { Name = "Charlie", Age = 25 } };
// 函数式查询:过滤、投影、排序 var result = people .Where(p => p.Age >= 18) // 过滤(谓词) .OrderBy(p => p.Name) // 排序 .Select(p => new { p.Name, IsAdult = true }) // 投影(匿名类型) .ToList();
foreach (var item in result) { Console.WriteLine($"{item.Name} - Adult: {item.IsAdult}"); } // 输出:Alice - Adult: True, Charlie - Adult: True }
public class Person { public string Name { get; set; } public int Age { get; set; } }}关键 LINQ 操作符:
Where— 过滤(类似filter)。Select— 转换(类似map)。Aggregate— 归约(类似reduce)。Any、All— 条件检查。
重要的是要记住 延迟执行。