C#的泛型委托与闭包函数

前些天Wendy问我说Func<T, ResultT>是个什么意思,初学C#都觉得这样的写法很奇葩,甚至觉得这样写有点诡异,其实以我来看,这是体现C#函数式编程的又一个亮点。

MSDN上我们可以找到这个所谓的泛型委托的解释。委托是C#较之于Java多出来的概念之一,C# 1.0的委托大体上看来就是一个函数指针,但是随着语言发展从委托衍生出来了多播委托和事件。

参考F#函数,我们其实更好理解C#里面的泛型委托。举个例子:

let x x y = x + y

这个F#的语句声明了一个接收两个整型参数并返回一个整型值的函数x。它的函数特征为

val x : x:int -> y:int -> int

F#借助强大的类型推断,我们可以像写数学函数一样书写函数,C#就不同了,C#并不是一门以函数是程序设计为主的程序设计语言,所以我们需要把类型给标注出来,于是就是:

Func<int, int, int> x = (j, k) => j + k;

可以看出来,我们写的Func<int, int, int>就是F#里所谓的函数的特征值。在函数式程序设计里,更强调不可变,比如在F#中,我们仅使用let绑定的值都属于不可变值,如果需要使用变量,那么我们需要诉之于可变性,也就是需要使用let mutable的绑定方法来绑定值。在函数是程序设计领域内并欢迎使用可变值,因为这样可能带来更多的隐患,尤其是全局变量,牵一发而动全身会导致程序后期难以控制。

虽然现在C#对于作用域的控制比较严格,但是总有一些时候我们得初始化一堆变量,后面还在不断引用,稍不注意就可能产生意外的结局,但是借助泛型委托,我们可以把函数式程序设计的优点糅合进C#里。

举个例子:

class Complex
{
    public Double Re{ get; set; } = 0;
    public Double Im{ get; set; } = 0;
    public Double Modulus => System.Math.Sqrt (Re * Re + Im * Im);
    private static Func<Complex, Complex> RequestConjugate() => x => new Complex{ Re = x.Re, Im = -x.Im };
    public Complex Conjugate() => RequestConjugate () (this);
}

注意到RequestConjugate,它只返回了一个泛型委托而不是真正返回了一个共轭复数。而Conjugate方法却很诡异RequestConjugate () (this),出现了两个括号,而第二个括号其实是传入了x作为参数,这样就实现了一个闭包,我们可以动态创建函数并把它当成返回值返回,并在需要使用的地方使用上。

似乎这个例子有点脱裤子放屁的感觉,直接return一个Complex不就得了么...

posted @ 2015-06-18 19:14  Johnwii  阅读(...)  评论(... 编辑 收藏