C# 3.0新语言特性和改进(上)

2009年3月8日星期日

C# 3.0新语言特性和改进(上)

在2007年11月19日,微软发布了Visual Studio 2008 和.NET 3.5。带来了很多新东西,比如ASP.NET3.5、LINQ、Silverlight、ASP.NET 3.5 Extensions等等,我们要跟紧着微软的步伐,很多的东西不得不从头开始学习了。总体来说,Visual Studio 2008和.NET 3.5是建立在.NET2.0核心的基础之上,C# 3.0新语言特性在.NET2.0基础上进行了改进,这些改进的功能可以大大简化我们编写程序。
C# 3.0新语言特性和改进包括:

自动属性(Auto-Implemented Properties)
隐含类型局部变量(Local Variable Type Inference)
匿名类型(Anonymous Types)
对象与集合初始化器(Object and Collection Initializers)
扩展方法(Extension Methods)
Lambda表达式和Lambda表达式树 (Lambda Expression and Lambda Expression Trees)
下面我就把C#3.0中的新特性的要点列出来,以供大家快速浏览。


  第一个特性:隐式类型化本地变量


  这个特性非常简单,有些JavaScript的影子,我们可以统一使用使用"var"关键字来声明局部变量,而不再需要指明变量的确切类型了,变量的确切类型可通过声明变量时的初始值推断出来。这样一来,可以大大简化我们声明局部变量的工作量了,下面是一个例子:


  class LocalVariables : AppRunner.AbstractApplication


  {


  public override void Run()


  {


  var intValue = 5;


  var stringValue = "This is a string";


  var customClass = new LocalVariables();


  var intArray = new int[3] { 1, 2, 3 };


  foreach (var value in intArray)


  Console.WriteLine(value);


  }


  }


  上面的代码将被解析成:


  class LocalVariables : AppRunner.AbstractApplication


  {


  public override void Run()


  {


  int intValue = 5;


  string stringValue = "This is a string";


  LocalVariables customClass = new LocalVariables();


  int[] intArray = new int[3];


  foreach (int value in intArray)


  Console.WriteLine(value);


  }


  }


  要特别注意的是,由于变量的类型是通过变量初始值推断而来的,所以在声明变量的同时必需为变量指定初始值。并且,变量并不是没有类型的,变量一旦初始化之后,类型就确定下来了,以后就只能存储某种类型的值了,比如上面的stringValue的类型经推断为string,所以该变量就只能保存string类型的值了。


  第二个特性:匿名类型


  有些时候我们需要临时保存一些运算的中间结果,特别是当这些中间结果是由多个部份组成时,我们常常会去声明一个新的类型,以方便保存这些中间结果。表面上看起来这很正常,而细想之后就会发现,这个新类型只服务于这个函数,其它地方都不会再使用它了,就为这一个函数而去定义一个新的类型,确实有些麻烦。


  现在,C#3.0中的匿名类型特性就可以很好的解决上面提到的问题,通过匿名类型,我们可以简单使用new { 属性名1=值1, 属性名2=值2, ..... , 属性名n=值n }的形式直接在函数中创建新的类型,看下面这个例子:


  class AnonymousType : AppRunner.AbstractApplication


  {


  public override void Run()


  {


  var anonymousType1 = new {


  CardNumber = "10001", Name = "van’s", Sex = true


  };


  Console.WriteLine(anonymousType1.CardNumber);


  Console.WriteLine(anonymousType1.Name);


  var anonymousType2 = new {


  CardNumber = "10002", Name = "martin", Sex = true


  };


  anonymousType2 = anonymousType1;


  }


  }


  在新类型中只能有字段成员,而且这些字段的类型也是通过初值的类型推断出来的。如果在声明新的匿名类型时,新类型的字段名、顺序以及初始值的类型是一致的,那么将会产生相同的匿名类型,所以上例中anonymousType1和anonymousType2的类型是相同的,自然能进行anonymousType2=anonymousType1的赋值。


  第三个特性:隐式类型化数组


  这个特性是对隐式类型化本地变量的扩展,有了这个特性,将使我们创建数组的工作变得简单。我们可以直接使用"new[]"关键字来声明数组,后面跟上数组的初始值列表。在这里,我们并没有直接指定数组的类型,数组的类型是由初始化列表推断出来的。


  class AnonymousTypeArray : AppRunner.AbstractApplication


  {


  public override void Run()


  {


  var intArray = new[] { 1, 2, 3, 4, 5 };


  var doubleArray = new[] { 3.14, 1.414 };


  var anonymousTypeArray = new[] {


  new { Name="van’s", Sex=false, Arg=22 },


  new { Name="martin", Sex=true, Arg=23 }


  };


  Console.WriteLine(intArray);


  Console.WriteLine(doubleArray);


  Console.WriteLine(anonymousTypeArray[0].Name);


  }


  }


  上面的代码中,anonymousTypeArray变量的声明同时运用了隐式类型化数组和匿名类型两种特性,首先创建匿名类型,然后再初始值列表,推断出数组的确切类型。


  第四个特性:对象构造者


  我们在声明数组时,可以同时对其进行初始化,这样就省去了很多麻烦,但是在创建类的对象时,这招可就不灵了,我们要么调用该类的构造函数完成对象的初始化,要么就手工进行初始化。这两种方法都不太方便,使用构造函数来对对象进行初始化时,我们为了某种灵活性,可能需要编写构造函数的多个重载版本,实在是麻烦。


  C#3.0中加入的对象构造者特性,使得对象的初始化工作变得格外简单,我们可以采用类似于数组初始化的方式来初始化类的对象,方法就是直接在创建类对象的表达式后面跟上类成员的初始化代码。具体示例如下:


  class Point


  {


  public int X { get; set; }


  public int Y { get; set; }


  public override string ToString()


  {


  return "(" + X.ToString() + ", " + Y.ToString() + ")";


  }


  }


  class Rectangle


  {


  public Point P1 { get; set; }


  public Point P2 { get; set; }


  public Rectangle()


  {


  P1 = new Point();


  P2 = new Point();


  }


  public override string ToString()


  {


  return "P1: " + P1 + ", P2: " + P2;


  }


  }


  class ObjectBuilder : AppRunner.AbstractApplication


  {


  public override void Run()


  {


  Point thePoint = new Point() { X = 1, Y = 2 };


  Console.WriteLine("Point(X, Y) = ", thePoint);


  Rectangle theRectangle = new Rectangle() {


  P1 = { X = 1, Y = 1 }, P2 = { X = 100, Y = 200 }


  };


  Console.WriteLine(theRectangle);


  }


  }


  我们在定义Point类的X和Y属性时,只须写上该属性的get和set访问器声明,C#编译器会自动为我们生成默认的get和set操作代码,当我们需要定义简单属性时,这个特性非常有用。


  我们以new Point() { X = 1, Y = 2 }语句,轻松的完成了对Point类的初始化工作。在创建类的对象时,我们可以按照需要去初始化类的对象,只要在类的创建表达式后跟上要初始化属性的列表即可,且可以只对需要初始化的属性赋初值,而无需把所有属性的初始值都写上去。


  在theRectangle对象的初始化表达式中,我们首先对P1属性进行初始化,然而P1属性也是一个自定义的类型,所以P1属性的初始化是另一个类型(Point)的初始化表达式,我们可以这样的方式来对更加复杂的类型进行初始化。


  

0 评论:

发表评论