zoukankan      html  css  js  c++  java
  • 初探C# 3.0 (1) 隐式类型变量, 扩展方法, Lambda表达式

    一.    隐式类型变量 (Implicitly typed local variables)

    这个特性应该是C# 3.0 中最Simple的特性了, 它能让你使用一个新的关键字 “var” 来声明变量(不能用来声明字段), 例如:
            var i = 5;
            var str = “Csharp”;
            var list = new List<int>();

    而我们的编译器做的事情只是吧那个var换成了对应的类型, 上面的代码和下面的完全等价:
            int i = 5;
            string str = “Csharp”;
            List<int> list = new List<int>();

    所以, 使用var声明变量必须带有变量的初始化语句, 因为这样编译器才能知道变量的类型, 当然更不能用null初始化.. 编译器并不知道这个null是什么类型的null, C# 3.0 虽然带来了一些动态的特性, 但C#始终是个强类型的语言.

    再说两句:
    如果在你的程序中有一个叫var的类型, 那你就不能再用这个关键字了.. 所以… 呃, 你知道的..
    这个语法产生的便利是否真的有价值呢? Of course! C#团队都做出来了… 可是当你去查看一个用var声明的变量的类型时, 却要向变量名称的右边看, 会不会有点不爽呢?

    二.    扩展方法 (Extension methods)

    哦耶, 又是一个语法糖, 不过这个特性比上一个的var似乎要更甜一些, 它甚至能让你在没有源代码的情况下给类添加方法! 看看以下的调用:
            int num = int.Parse(textBox.Text);

    上面那句代码你肯定已经写过N遍了, 你知道任何东西都有一个ToString方法, 但你肯定没想到今天我们的string也有了ToInt方法! 就像下面写的:
            int num = textBox.Text.ToInt();

    要办到它, 在C# 3.0里很简单, 你只需要在一个static类里写这么一个方法便行了:
            static class MyExtensions
            {
                   public static int ToInt(this string str)
                    {
                        return int.Parse(str);
                    }
            }

    然后在最新的Visual Studio Orcas beta 1里, 随便在一个string对象后面输入一个点, 你就会发现这个ToInt方法了.
    编辑器怎么知道这个ToInt是string的扩展方法呢?
    1.    这个方法是static的
    2.    这个方法写在一个static类里
    3.    这个方法的第一参数类型是扩展方法所扩展的类型, 且在参数前有关键字this

    当然扩展方法不是只能有一个参数的, 更多的参数声明在this参数之后就行了, 例如:
            static class MyExtensions
            {
                       public static int ToInt(this string str, int time)
                        {
                            return int.Parse(str) * time;
                        }
            }

    于是可以这样调用它:
            int two = “1”.ToInt(2);

    扩展方法是怎么实现的呢? 其实很简单, 比如上面那句的调用在编译器的眼里和下面一句是完全等同的:
            int two = MyExtensions.ToInt(“1”, 2);

    显然, 我们还是没有改变string类, 当然也就不能像string本身的方法一样访问它的私有信息了 :(
    虽然扩展方法也不是太高深, 但它在C# 3.0的编程实践中还是有很多体现的, 比如自带的一些对于可迭代类型的扩展方法, 都是很实用的:



    三.    Lambda 表达式 (Lambda expression)

    先看一段有Lambda表达式的代码:
            static void Main(string[] args)
            {
                int[] lotNums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                var evens = lotNums.Where(n => n % 2 == 0);
                foreach (var e in evens)
                {
                    Console.WriteLine(e);
                }
            }

    这些代码的功能是: 从一堆数字中选出偶数并输出.
    想想看如果要用C# 2.0的语法我们应该怎么做? 定义一个List<int>, 迭代整个数组, 如果这个数字对2取余等于0就扔到那个List里. 这些代码起码要写N行(N >= 1),是吧?
    但C# 3.0的语法把却真正把上面的操作浓缩成了一行代码:
            var evens = lotNums.Where(n => n % 2 == 0);

    lotNums这个数组调用了一个叫Where的扩展方法, 这个扩展方法是 .NET Framework 3.5的BCL中自带的, 看看它的声明:
            public static IEnumerable<TSource> Where<TSource>
                                (this IEnumerable<TSource> source, Func<TSource, bool> predicate);

    是一个泛型方法, 可是上面的调用并没有写<int>啊, 这是因为在C# 3.0的编译器比2.0的聪明很多, 既然你传进来的是IEnumerable<int>, 我调用的当然是Where<int>了..这种语法特性可以让你少写很多冗余的东西.

    Where方法是传进来两个参数, 一个是原来的集合, 另一个是筛选偶数用的一个delegate, 也就是Func, 这里使用的两个泛型参数的Func委托类型的声明是:
            public delegate TResult Func<TArg0, TResult>(TArg0 arg0);

    Where 的第二个参数类型Func<TSource, bool> 指的是这样一个委托: 传入TSource对象, 返回一个bool值, 显然程序中的那句Lambda表达式n => n % 2 == 0就对应了Where的第二个参数predicate. 于是我们可以猜想 n => n % 2 == 0 的前一个n就是Func<int, bool>委托的int类型的传入的参数, 而返回的bool值就是n % 2 == 0.

    其实把 var evens = lotNums.Where(n => n % 2 == 0) 改写成C# 2.0的语法能更容易理解Lambda语法的使用:
            IEnumerable<int> evens = Enumerable.Where(lotNums,
                                                              delegate(int n) { return n % 2 == 0; } );

    噢. 原来Lambda表达式就是匿名方法...
    是的, 准确的说是可以少写一些代码的匿名方法.
    以上所用到的Lambda表达式是最简单的写法, 还有更复杂的Lambda表达式的写法,比如可以设置多个参数, =>操作符后可以有大括号扩起的一堆语句, 你可以参考C# 3.0规范或者其他文档, 总之, 匿名方法能表达的, Lambda表达式都能表达.


    四.    再说两句

    C# 3.0 所有的特性都是编译器层面上的改进, 编译出的IL以及执行它的CLR都没有任何改变, 所有的语言新特性也只是越来越方便编码,让代码更好写更好读. C#看上去越来越美了……
    C# 3.0 还有好几个特性以后再慢慢再说, 其实LINQ就是这所有基本特性的一个组合.

  • 相关阅读:
    linux安装mysql5.7.24
    如何解决svn Authorization failed错误
    vux配置i18n
    vue项目使用vux框架配置教程
    EL函数
    Android的taskAffinity对四种launchMode的影响
    Activity生命周期-Android
    为什么用服务不用线程-Android
    Hibernate总结--MyEclipse的小bug
    EL表达式隐含对象
  • 原文地址:https://www.cnblogs.com/Dah/p/CSharp3_ImplicitlyTyped_ExtensionMethod_LambdaExpression.html
Copyright © 2011-2022 走看看