首页 > 代码库 > 面向对象设计——原来“Lambda表达式”是这样来的

面向对象设计——原来“Lambda表达式”是这样来的

在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法。 C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式。
——MSDN

以上是来自MSDN中的话,可以看出声明委托的这样一个发展:命名方法→匿名方法→Lambda表达式。下面通过代码展示一下他们是如何进化的。



命名方法


对于更高层次的面象对象而言,委托是必须。那么,我们就以实现“求两个数中的最大数”为例看最原始的委托实现方式。

声明一个成员方法:

public int CompareTwoValue(int a, int b)
{
    if (a > b)
    {
        return a;
    }
    else
    {
        return b;
    }
}

再声明一个委托:

public delegate int deleMethod(int a,int b);

通过委托调用上面的成员方法。注意一点的是方法的参数类型和返回类型必须与委托的参数和返回类型相匹配。本例中成员方法和委托都是输入两个int值而输出一个int值。

public int Show()
{
    deleMethod max = new deleMethod(CompareTwoValue);    //实例化
    return max(5, 10);                                   //调用
}


匿名委托


也称作匿名方法,其实,这只是一种语法形式上的变化,因为编译的时候,还是要进行类型匹配的,那么对于上面的Show方法,我可以使用匿名委托的方式来表达。 

<pre name="code" class="csharp">public int Show()
{
    deleMethod max = delegate(int a, int b)
    {
        if (a > b)
        {
            return a;
        }
        else
        {
            return b;
        }
    };
    return max(5, 10);
}

很显然,我们看不到命名的地方,通过匿名的方法,使语法形式上简便了,但觉得匿名委托在C#2.0中并没有实质性的用处,只有到3.0时,涉及到Lamda表达式时,才真正的有用处。

Lambda表达式

用Lamda表达式写上面的方法:

public int Show()
{
    Func<int, int, int> max = (a, b) =>
    {
        if (a > b)
        {
            return a;
        }
        else
        {
            return b;
        }
    };
    return max(5, 10);
}

Lamda表达式只是匿名委托的一种表现形式。可以很直观的看出,三种方式中,Lamda表达式编写的代码量最少。


由于我们已经注明max的类型是Func<int, int, int>,因此C#编译器可以明确地知道a和b都是int类型,于是我们就可以省下参数之前的类型信息。这个特性叫做“类型推演”,也就是指编译器可以自动知道某些成员的类型。请不要轻易认为这个小小的改进意义不大,事实上,您会发现Lambda表达式的优势都是由这一点一滴的细节构成的。那么我们再来一次改变:
Func<int, int, int> max = (a, b) => a > b ? a : b;
如果Lambda表达式的body是一个表达式(expression),而不是语句(statement)的话,那么它的body就可以省略大括号和return关键字。此外,如果Lambda表达式只包含一个参数的话,则参数列表的括号也可以省略,如下:
Func<int, bool> positive = a => a > 0;
如今的写法是不是非常简单?那么我们来看看,如果是使用delegate关键字来创建的话会成为什么样子:
Func<int, bool> positive = delegate(int a)
{
    return a > 0;
};
您马上就可以意识到,这一行和多行的区别,这几个关键字和括号的省略,会使得编程世界一下子变得大为不同。(当然,Lambda表达式也并不是可以完全替代delegate写法,例如带ref和out关键字的匿名方法,就必须使用.NET 2.0中的delegate才能构造出来了。)


总结

就一句话:既可以提高可读性,又能够减少代码数量,我实在找不出任何理由拒绝Lambda表达式。

面向对象设计——原来“Lambda表达式”是这样来的