c# 3.0 初体验 1

来源:互联网 发布:轻量级看图软件 编辑:程序博客网 时间:2024/05/01 17:09

      大家可能都回抱怨为什么c#发展的回这么快呢?可能有很多的人连2.0都没有深入的接触,是的,我们已经有了3.0了。不用抱怨,因为c#比起来其他的一些语言来说太“年轻”了,所以它当然有很多需要改进的地方,需要提高的地方。在二三年前,大家都觉得其实c#就是microsoft从java抄袭过来一个面向对象的语言,可以从近几年的发展来看,java的速度已经明显跟不上c#的脚步了。比如java5.0中的泛型,看起来更像是sun给java的framework打的一块补丁而已,严格来说java的泛型是假的,因为当你编译一个Java泛型类时,编译器会将所有的类型参数替换为Object。当然,如果你尝试建立一个List<int>,你就需要对所有的int进行装箱。因此,这会有很大的开销。另外,为了让VM高兴,编译器必须为所有的类型插入类型转换。如果一个List是Object的,而你想将这些Object视为Customer,就必须将Object转换为Customer,以让类型检查器 满意。而它在实现这些的时候,真的只是为你插入所有这些类型转换。因此,你只是尝到了语法上的甜头,却没有获得任何执行效率。当然我不是有意贬低java语言,而是从某一个侧面来看问题,大家不要因此来骂我。说到底,我觉得变化是好事情,也就是微软正在为它的c#语言不断的完善,作为程序员,我们不能简单一劳永逸,而是要随时最好充电的准备,你准备好了吗?好了,言归正传,我们开始我们的c#3.0初体验,在第一次我们主要看一下,这次微软又为我们带来了什么新的东西,并且对将来的开发人员来说会有哪些方便呢?顺便说一句,我进入第一家公司一直都是在.net framework 1.1上开发,2.0上的新特性都是自己学的,现在才有了用武之地。

C#3.0主要的语言上新特性有以下:

       ●匿名类型(还记得2.0中的匿名方法吗?哈哈,真搞)

       ●隐含类型局部变量

       ●扩展方法

       ●表达式树

       ●对象与集合初始化器

       ●查询表达式(LINQ)--绝对是牛鼻的东西

       ●Lambda表达式

        这些只是一些从开发人员角度来说的东西,如果从平台方面来看,微软对它的虚拟机在性能上的提升也是值得我们关注的。接下来我们一个一个来解释一下。

隐含类型局部变量

        有过vb经验的朋友对这条一定很熟悉,看以下表达式:

       var i=5;

       var s="qigaoopan";

       var ym=new[] {2423,234,7456};

       var为关键字,他不是一个类型,我们可以看作一个占位符号,编译器会在编译的时候进行类型的推断,来确定我们到底申明了什么类型。初始化的右边必须是一个表达式,并且编译时可以推断类型。比如我们var b=null,编译的时候就会出现编译错误。如果有人变态真写出一个自定义类型var,那么编译器会以系统var为最高优先级别来处理,说到这里,希望大家注意c#的编码规范。类型的命名不能和系统的关键字冲突。并且var的申明仅仅限制与局部变量的申明,我们也可以用在foreach循环和using语句中。在foreach我们的编译器会自动推断集合中的元素的实际的类型,我们这样写的代码在通用性上有很大的提高,这些技巧也可以提高代码的复用性。也就是代码的抽象层次提高了。但是我们不能狂用这些trick,会对代码的性能有很大的损伤。看最后一个例子,数组也可以作为隐含类型,以前版本的c#中我们肯定不能这样干,但是现在我们可以了,编译器可以自动推断这个数组的类型,int[]数组。如果我们的数组中的类型不统一,那么在编译的时候我们就会遇到编译错误,即隐含类型推断的时候出现了问题,我们说所有的类型都是从object来的,可以把所有的类型都转化到object,但是编译器是不会做这样自动的转换的。也就是编译器不会把隐含类型的数组转换成object数组。

       总结一下这个特征就是,它是一个编译时的小功能。

扩展方法

      顾名思义,扩展方法允许我们在不改动源代码的情况下扩展现有类型中的实例方法。(感觉类似动态语言的特征)看下边的例子:

     public static class Qigaopan{

              public static void Study(this string s){

                           ......................
   }

  }

  String s="Microsoft ,Go";

        s.Do();

       大家可能注意到了Study方法中的this参数,其实我们在s上调用Do方法的时候会传递s进入方法,相当于Qigaopan.Do(s)。

  注意我们是在不改变源代码的情况下去添加的,也就是在二进制不受破坏的前提下作的这种扩展。注意我们一定要使用静态类,只有静态类中才有静态方法。扩展一个类的方法我们一般有:通过继承,包含的方式,即组合的方式,第三种就是反射技术。我们可以通过在运行时通过反射来添加一些新的特性到类上。在3.0种微软为我们带来第四种方法。就是我们上边看到的扩展发放,我们只能通过这种发式扩展,而不能收缩。

  总结以下就是扩展方法的本质是将实例方法调用在编译期间改变为静态类的静态方法的调用,扩展方法是一种编译时技术,我们不能过度的使用,注意和反射技术的区别。扩展方法并不是对设计的颠覆,只是给我们提供了一些更加灵活的来加强我们的设计,而不是鼓励我们不用认真地去设计。我们在设计的时候不能依赖于扩展方法,其实扩展方法就是一种对设计的弥补。比如我们的adapter设计模式,我们在现有代码的基础上去做转换的时候才会用到,如果让我们重新去设计,我们肯定不会去在用adapter模式了。很显然我们在上便的QIgaopan类型中扩展了string类型的方法,我们不能再一个类型中扩展好几个类型,比如在添加和一个方法叫做public static void YM(this int i){}这样的东西,这就违背了语言的初衷。

对象和集合初始化器

  我们在编写类型的时候会写一些构造器,有了对象初始化器,我们可以有以下代码:

  public class Point{  

    int x,y;

    public int X{get......}

    public int Y{get.......}

   }

   var a=new Point{X=0,Y=1}

   相当于:var a=new Point();a.X=0;a.Y=1;

   集合初始化器:List<int> num=new List<int>{0,1,2,3,4,5};这也是一中编译时的转换技术,可以使我们以更加方便的方式来初始化集合。

   总结下:对象初始化器实际上利用了编译器对对象中对外可见的字段和属性进行按序赋值;集合初始化器会对初始化器中的元素进行按序调用add方法。

匿名类型

  看例子:var qi=new {Name=“qigaopan”,Age=“25”,Marrige=“no”};

var qi1=new {Name=“qigaopan”,Age=“24”,Marrige=“no”}

qi=qi1;

  编译器可以通过第一句推断出我们的类型中有什么东西,首先是两个属性,然后是两个字段,还有一个无参数的构造器。类似于我们申明了这样一个类型:

class TypeName{ 

   public string Name{get,set}

   public string Age{get,set}

   public string Marrige{get,set}

   public string name,age,marrige;

  }

  其实匿名类型使用new来创建了一个匿名的对象,这就给我们提供了一中更加方便的方式。以前我使用一个简单的类型的时候要写一大堆的属性,现在我们直接使用,编译器会知道我们的意图,而构建一个合适的类型来给我们使用。匿名类型直接继承自System.Object。其实就如同我们上公共汽车一样,我们拿出来钱根本不需要告诉售票员我们要买票,售票员就会知到我们的意图。如之前的例子我们指定了连个属性相同的匿名类型,那么他们会使同一个类型,比如qi和qi1是同一个类型。

  我们只是说了语法的表面现象,我们不能只看表面,而要看语言机制,然后我们提升某个语言机制的认识,我们要站在更高的一个层次来看一种语言的某个机制如何使用,内在机制,由这种机制提炼出来的某种管用法,一种模式,也就是我们如何更好的使用这种机制。任何一种机制都是一把双刃剑,有好的方面,也有不好的一个方面。所以感觉在编写代码向上的方向上,我们一定要注意对机制的把握。

一看时间都快12:30了,呵呵,睡觉了,有时间继续和大家分享3.0。写的不对的地方希望大家只出来。

原创粉丝点击