C#中的函数式编程:链式调用与错误处理

在编程中,理解代码的执行流程至关重要。通常,习惯于从上到下顺序阅读代码,跟随所有的if-else、try-catch等分支结构。然而,这种阅读方式往往需要理解大量的技术细节,例如null值检查。那么,能否编写一种代码,它能够从左到右顺序阅读,并且原则上不涉及技术细节,就像一系列操作那样直观易懂呢?F#中的管道操作就是这样一种概念。

在F#中,管道操作看起来是这样的:

let squared = Numbers |> List.filter isOdd |> List.map square;;

对象Numbers通过一系列函数进行处理。在C#中,也希望实现类似的功能。

在C#中,可以使用委托来实现类似的功能,但委托不是泛型的。现在,可以使用泛型,同时也希望处理错误和null值。Tomas Petricek和John Skeet的《Real-World Functional Programming》提供了解决方案。关键在于两个方面:Option类型和仅使用一个固定的接口:

Func<Option<T>, Option<T>>

这意味着传入一个函数,它接收一个Option并返回一个Option。这个接口可以无限链式调用或管道化。

Option类型在F#中非常常见。Option可以是None或Some。Some封装了一个实际的业务对象。Continuation是一个将函数的结果传递给另一个函数的概念。如果将这两个概念结合起来,虽然涉及很多理论,但这里不深入讨论。如果将一个对象封装在Option中,然后使用Continuation,就可以像上面展示的AndThen代码那样继续链式调用。Option对象隐藏了它内部的实际类型。

在Option中可以是任何东西。使用Option概念,可以在严格类型语言中以泛型的方式行为。对于Continuation,可以使用Lambda表达式,但类型系统不会允许以泛型的方式实现它们。本文是关于以泛型方式实现Continuation的。

Option类型是一个抽象类,有两个具体实现:None和Some。None结束链式调用,Some封装了[SomeObject]。一个函数必须首先获取封装的对象,对其进行一些处理,然后返回一个None或Some,其中包含封装的对象。Option Some和None类是泛型的!

为了这个Option类型,添加了一些函数,比如上面的AndThenIfElse。如果看参数,会看到需要传入以下两个参数:

Func<Option<T>, Option<T>> tryFirst, Func<Option<T>, Option<T>> tryNext

添加了:

  • AndThen(continuation)。如果前一个函数返回Some,则继续执行以下函数。
  • AndThenCheck。传入的第一个参数是一个函数,它接受一个Option并返回一个Boolean。如果这个Boolean为true,则执行第二个参数,这是一个continuation。如果不是true,则返回None。
  • AndThenCaseCheck。传入一个AndThenCheck的列表。如果一个检查返回true,则执行相应的continuation。如果没有一个检查返回true,则返回None。在附带的例子中,使用lambda表达式来组合这个列表。Funcs可以被lambda表达式替换,在这种情况下,认为这是一个好主意。
  • AndThenIfElse。传入两个函数。如果第一个返回None,则执行第二个continuation。

另一个有趣的要点是,上述continuation的管道不会执行,直到调用Exec()。这样做的原因是,因为异常是在Exec()调用中处理的,并且continuations在第一个None返回时停止。实际上,管道是一个MultiCastDelgates的数组列表,可以序列化。option/Continuation概念也可以在其他场景中使用,例如通过保存直到触发时间来推迟执行。

添加了一个如何在现实世界中使用它的具体例子。代码本身并没有做太多,但给一个很好的想法如何使用它。查看下面的代码(ClientController),可以看到真正的好处:

someClientData.AndThen(isValid) .AndThen(ClientBusiness.Save) .AndThenIfElse(ClientBusiness.CheckOnDustin, ClientBusiness.CheckOnNotDustin) .AndThenCheck(ClientBusiness.ANameLengthCheck, ClientBusiness.GetLastOneInLocality) .AndThenCaseCheck(ClientBusiness.SomeCaseListOnProfession()) .Exec();
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485