C# 函数式编程:原理与示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C#中的函数式编程:从理论到实践

函数式编程(FP)是一种将计算视为数学函数求值的编程范式,它避免改变状态和可变数据。尽管C#最初是一种面向对象的语言,但从3.0版本开始,它一直积极融入函数式特性。如今,C#支持lambda表达式、LINQ、不可变类型甚至模式匹配等概念。在本文中,我们将深入探讨FP的关键原则,并展示如何在实际的C#项目中应用它们。



1. 纯函数与无副作用

纯函数是指满足以下条件的函数:

  • 对于相同的参数始终返回相同的结果(引用透明性)。
  • 没有副作用(不修改全局状态、不写入文件、不发送HTTP请求)。

在C#中,纯函数可能如下所示:

public static int Add(int a, int b) => a + b;

以下是一个非纯函数的示例:

public static int AddAndLog(int a, int b){    Console.WriteLine($"Adding {a} and {b}"); // 副作用    return a + b;}

纯函数的优势:易于测试、调试和并行化。



2. 不可变性

在FP中,数据默认是不可变的。在C#中,这可以通过以下方式实现:

  • 为字段使用readonly关键字。
  • record结构(C# 9+),它自动创建不可变对象。
  • 来自System.Collections.Immutable命名空间的集合。

使用record的示例:

public record Person(string Name, int Age);

如果需要更改年龄,则会创建一个新实例:

Person person = new("Ivan", 30);Person olderPerson = person with { Age = 31 };

不可变性可以防止意外的变更并简化多线程处理。



3. 高阶函数与Lambda表达式

高阶函数将其他函数作为参数或返回函数。在C#中,这通过委托Func<>、Action<>、Predicate<>来实现。

一个简单的例子是LINQ中的Where方法:

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

这里,n => n % 2 == 0是一个lambda表达式(匿名函数)。

你可以编写自己的高阶函数:

public static List<T> Filter<T>(List<T> list, Func<T, bool> predicate){    var result = new List<T>();    foreach (var item in list)        if (predicate(item)) result.Add(item);    return result;}


4. LINQ:强大的函数式风格工具

LINQ(语言集成查询)可能是C#中函数式编程最突出的示例。它允许你以声明式的方式处理集合,类似于SQL。

示例:获取年龄大于18岁的用户名,并按年龄排序:

var users = new List<User>{    new("Anna", 22),    new("Boris", 17),    new("Victor", 30)};

var result = users .Where(u => u.Age >= 18) .OrderBy(u => u.Age) .Select(u => u.Name) .ToList();

LINQ支持惰性求值,从而节省资源。



5. C#中的Monad与Maybe类型

Monad是一种用于链式处理带上下文计算的抽象(例如,处理null或异步)。C#没有内置的Maybe monad,但很容易实现:

public class Maybe<T>{    private readonly T _value;    public bool HasValue { get; }        p                

博客

书籍推荐