zoukankan      html  css  js  c++  java
  • 委托发展史(三)

    通过C#2极大的简化了委托的使用。如果仅仅是为了简化事件的订阅以及增强可读性,这些技术确实已经足够了。

    但是,C#2中的委托仍然过于臃肿:一页充满匿名方法的代码,读起来真让人难受,你也肯定不愿意经常在一个语句中放入多个匿名方法吧。

    C#3可以说是一个工业革命。

    *作为委托的Lambda表达式

    从许多方面Lambda表达式都可以看做是C#2的匿名方法的一种演变。

    匿名方法能做到的几乎一切事情都可以用Lambda表达式来完成,另外,几乎所有情况下,Lambda表达式都更易读,更紧凑。

    从最显而易见的方面看,两者并无多大区别--只是Lambda支持许多简化语法使他们在常规条件下显得更简练。

    与匿名方法相似,Lambda表达式有特殊的转换规则:表达式的类型本身并非委托类型,但它可以通过多种方式隐式或显式转换成一个委托实例。

    匿名函数这个术语同时涵盖了匿名方和Lambda表达式--,在很多情况下,两者可以使用相同的转换规则。

    慢慢来看这一场工业革命吧。。。

    *Func<...>委托类型简介

    在.NET3.5的System命名空间中,有5个泛型Func委托类型,

    Func并无特别之处——只是他提供了一些好用的预定义泛型类型,在很多情况下能帮助我们处理问题。

    每个委托签名都获取0~4个参数,其类型用类型参数来指定。最后一个类型参数用作每种情况下的返回类型。

    通俗讲就是这个Func是一个有返回值委托类型。

    看一下.NET3.5所有Func委托的签名:

    public delegate TResult Func<TResult> ();
    public delegate TResult Func<T,TResult> (T arg);
    public delegate TResult Func<T1,T2,TResult> (T1 arg1,T2 arg2);
    public delegate TResult Func<T1,T2,T3,TResult> (T1 arg1,T2 arg2,T3 arg3);
    public delegate TResult Func<T1,T2,T3,T4,TResult> (T1 arg1,T2 arg2, T3 arg3, T4 arg4);

    例如,Func<string,double,int>  等价于以下形式的委托类型。

    public delegate int TestDelegate(string arg1, double arg2);

    当你想返回void时,也就是无返回值,可使用Action<...>系列委托,其功能相似。

    Action在.Net2.0中就有了,但其他都是.NET 3.5新增的。如果4个参数还嫌不够,.NET 4将Action与Func家族扩展为拥有16个参数。

    因此Func<T1,..., T16 , TResult >拥有17个参数类型。

    例如,我们需要获取一个stirng参数,并返回一个int,所以我们将使用Func<string,int>。

    *转换到Lambda表达式

    Func<string, int> returnLength;
    returnLength = delegate (string text) { return text.Length; };
    Console.WriteLine(returnLength("Hello"));

    最后会输出"5",预料之中。

    注意上面的代码,returnLength的声明与赋值是分开的,否则一行可能放不下——除此之外,这样还有利于对代码的理解。所以,我们将它转换成Lambda表达式

    Lambda表达式最冗长的形式是:

    (显式类型的参数列表) => { 语句 }

    =>这个是C#3新增的,他告诉编译器我们正在使用一个Lambda表达式。Lambda表达式大多数时候都和一个返回非void的委托类型配合使用——如果不反悔一个结果,语法就不像现在这样一目了然。

    这个版本包含显式参数,并将语句放到大括号中,他看起来和匿名方法非常相似。

    Func<string, int> returnLength;
    returnLength = (string text) => { return text.Length; };
    Console.WriteLine(returnLength("Hello"));

    在阅读Lambda表达式时,可以将=>部分看成"goes to"。

    匿名方法中控制返回语句的规则同样适用与Lambda表达式:不能从Lambda表达式返回void类型;

    如果有一个非void的返回类型,那么每个代码路径都必须返回一个兼容的值。

    到目前为止,使用Lambda表达式并没有节省多大空间,或使代码变得容易阅读。

    *用单一表达式作为主体

    我们目前使用一个完整的代码块来返回值,这样可以灵活地处理多种情况——可以在代码块中放入多个语句,可以执行循环,可以从代码块中不同位置返回。。。等等

    这和匿名方法是一样的。

    然而,大多数时候,都可以用一个表达式来表示整个主体,该表达式是Lambda结果。(意思就是,一条语句就可以解决的事)

    这些情况下,可以指定那个表达式,不用大括号;不使用return语句,也不添加分号,格式随即变成:

    (显式类型的参数列表) => 表达式

    在我们的例子中,就变成了——

    (string text) => text.Length

    现在已经开始变得简单了,接着来考虑一下参数类型。编译器已经知道Func<string,int>的实例获取单个字符串,所以只需命名那个参数就可以了。

    感觉还是得分两行来声明跟赋值啊。。。

    *隐式类型的参数列表

    编译器大多数时候都能猜出参数类型,不需要你显示声明他们。这些情况下,

    还可以更加简便些。

    (隐式类型的参数列表) => 表达式

     嗯,更加简便了,Lambda表达式也变成了这样:

    (text) => text.Length

    隐式类型的参数列表就是一个以逗号分隔的名称列表,没有类型。但是隐式和显式类型的参数不能混合匹配——要么整个列表都是显式类型,要么都是隐式类型。

    如果存在out 或 ref参数,那么就只能是显式类型了。

    上面的Lambda表达式已经相当简短了,可以继续简化的地方不多了。

    哎~这个圆括号看起来有点多余啊。除去它!

    *单一参数的快捷语法

    如果Lambda表达式只需要一个参数,而且那个参数可以隐式指定类型,C#3就允许省略圆括号。这种Lambda表达式是:

    参数名 => 表达式

    因此我们的Lambda表达式最终形式是:

    text => text.Length

    这样的话如果一小段代码中含有多个Lambda,那么拿掉参数列表的圆括号之后,对于可读性来说是增强不少的。

    还有如果愿意,可以用圆括号将整个Lambda表达式括起来。

    在大多数情况下这种形式都是十分易读的,例如之前的例子写出来就是这样:

    Func<string, int> returnLength;
    returnLength = text => text.Length;
    
    Console.WriteLine(returnLength("Hello"));

    可能刚开始读起来有点"别扭",不过很快就习惯啦~

    当你习惯了Lambda表达式之后,你一定会感慨他们是多么的简洁,很难想象还可以使用更短,更清晰的方式老创建委托实例。

    *Lambda语法简写总结

  • 相关阅读:
    架构师养成记--34.Redis持久化
    架构师养成记--33.Redis哨兵、redis简单事务
    js获取当前项目根路径URL (转自CSDN 红领巾-sunlight)
    架构师养成记--32.Redis高级(安全 主从复制)
    架构师养成记--31.Redis的几种类型
    架构师养成记--30.Redis环境搭建
    oracle split(转自--博客园 linbo.yang)
    架构师养成记--29.redis开篇
    129、Java面向对象之static关键字一(修改static变量)
    128、Java面向对象之对象的比较
  • 原文地址:https://www.cnblogs.com/yingxl/p/9007428.html
Copyright © 2011-2022 走看看