3.4.1.1 在 C# 中传递函数作为参数值
我们知道,在 C# 中,把函数作为参数,可以使用委托实现,特别是 Func 委托。在清单 3.17 中的委托有两个整型的参数,返回的结果也是整型。这段代码表明,可以用递归方法实现聚合,以委托作为参数。
清单 3.17 计算列表中元素的和、积 (C#)
int AggregateList(FuncList<int> list,int init, Func<int,int,int> op) {
if(list.IsEmpty)
return init; [1]
else {
int rest = AggregateList(list.Tail, init, op); | [2]
return op(rest, list.Head); |
}
}
static int Add(int a, int b) { return a +b; } | 声明方法进行测试
static int Mul(int a, int b) { return a *b; } |
var list = FuncList.Cons(1,FuncList.Cons(2, | 初始化样本列表
FuncList.Cons(3, FuncList.Cons(4, |
FuncList.Cons(5, FuncList.Empty<int>()))))); |
Console.WriteLine(AggregateList(list, 0,Add)); | 和为 15
Console.WriteLine(AggregateList(list, 1,Mul)); | 积为 120
我们先看一下 AggregateList 方法,它的第一个参数取是要处理的列表,后面两个参数指定应该用输入做什么。第二个参数是初始值,为整数,当列表空时使用[1],从方法返回这个初始值。
最后一个参数是委托,用于另外一个分支[2]。这里,我们首先递归计算列表其余部分的聚合结果,然后,再调用 op 委托去计算这个结果和列表头的聚合。在后面的示例中,给定的参数既可以是加法,也可以是乘法。我们这里使用的委托类型是泛型Func<T1, T2, TResult> 委托, 来自 .NET 3.5,在第五章会有进一步地讨论。一句话,使用 .NET 的泛型,能够指定参数的类型和数量,以及返回类型。因此,当我们调用 op 时[2],编译器知道我们应提供两个整数作为参数,返回结果为整数。
在后面的代码中,我们声明了两个简单的方法,类型与委托一致:一个计算两个数字的和,另一个计算积。其余部分代码演示了如何调用 AggregateList 方法,得到的结果与我们前面的示例由 SumList 和 MultiplyList 返回的相同。
当然,以这种方式写的辅助方法,有点冗长乏味,因为在代码的其他任何地方都用不到。因此,为使代码更好一些,C# 2.0 使用了匿名方法;C# 3.0 有更优雅的方式,使用 lambda 表达式。Lambda 表达式和 F# 中的对应功能(称为 lambda 函数),几乎可以用在任何真正的函数代码中,因此,我们在第五章中会有更充分的讨论。在下一节,我们会看到本章最后一个代码示例,用 F# 实现相同的行为。