zoukankan      html  css  js  c++  java
  • C#3.0中的新特性

    转:http://baike.baidu.com/view/406857.htm

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

      这个特性非常简单,有些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

      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)的初始化表达式,我们可以这样的方式来对更加复杂的类型进行初始化。

      上篇文章中介绍了C# 3.0中比较简单的四个特性,分别是隐式类型化本地变量、匿名类型、隐式类型化数组,以及对象构造者,下面我将对C# 3.0中的较复杂,同时也是非常强大的几个特性进行介绍,供大家快速浏览。

    第五个特性:集合构造者

      我们可以在声明数组的同时,为其指定初始值,方法是直接在数组声明的后面跟上初始值列表。这样就使数组的初始化工作变得简单,而对于我们自己创建的集合类型,就无法享受到与普通数组一样的待遇了,我们无法在创建自定义集合对象的同时,使用数组的初始化语法为其指定初始值。

      C# 3.0中加入的集合构造者特性,可使我们享受到与普通数组一样的待遇,从而在创建集合对象的同时为其指定初始值。为了做到这一点,我们需要让我们的集合实现ICollection<T>接口,在这个接口中,完成初始化操作的关键在于Add函数,当我使用初始化语法为集合指定初始值时,C#编译器将自动调用ICollection<T>中的Add函数将初始列表中的所有元素加入到集合中,以完成集合的初始化操作。使用示例如下:

      class CollectionInitializer : AppRunner.AbstractApplication

      {

      class StringCollection : ICollection<string>

      {

      public void Add(string item)

      {

      Console.WriteLine(item);

      }

      // Other ICollection<T> Members

      }

      public override void Run()

      {

      StringCollection strings = new StringCollection() { "Van's", "Brog", "Vicky" };

      }

      }

      在这个示例中,编译器会自动为strings对象调用Add方法,以将初始值列表中的所有元素加入到集合中,这里我们只是简单将初始值列表中的元素输出到控制台。

    第六个特性:Lambda表达式

      C# 2.0中加入的匿名代理,简化了我们编写事件处理函数的工作,使我们不再需要单独声明一个函数来与事件绑定,只需要使用delegate关键字在线编写事件处理代码。

      而C# 3.0则更进一步,通过Lambda表达式,我们可以一种更为简洁方式编写事件处理代码,新的Lambda事件处理代码看上去就像一个计算表达式,它使用"=>"符号来连接事件参数和事件处理代码。我可以这样写:SomeEvent += 事件参数 => 事件处理代码;下面是完整的示例:

      delegate T AddDelegate<T>(T a, T b);

      class LambdaExpression : AppRunner.AbstractApplication

      {

      public static event EventHandler MyEvent;

      public override void Run()

      {

      MyEvent += delegate(object s, EventArgs e)

      {

      Console.WriteLine(s);

      };

      MyEvent += (s, e) => { Console.WriteLine(s); };

      MyEvent(this, null);

      AddDelegate<string> add = (a, b) => a + b;

      Console.WriteLine(add("Lambda", "Expression"));

      }

      }

      在上面的例子中,分别使用了匿名代理和Lambda表达式来实现同样的功能,可以明显看出Lambda表达式的实现更为简洁。我们在使用Lambda表达式编写事件处理代码时,无需指明事件参数的类型,且返回值就是最后一条语句的执行结果。

    第七个特性:扩展方法

      当我们需要对已有类的功能进行扩展时,我们通常会想到继承,继承已有类,然后为其加入新的行为。而C# 3.0中加入的扩展方法特性,则提供了另一种实现功能扩展的方式,我们可以在不使用继承的前提下实现对已有类本身的扩展,这种方法并不会产生新的类型,而是采用向已有类中加入新方法的方式来完成功能扩展。

      在对已有类进行扩展时,我们需将所有扩展方法都写在一个静态类中,这个静态类就相当于存放扩展方法的容器,所有的扩展方法都可以写在这里面。而且扩展方法采用一种全新的声明方式:public static 返回类型 扩展方法名(this 要扩展的类型 sourceObj [,扩展方法参数列表]),与普通方法声明方式不同,扩展方法的第一个参数以this关键字开始,后跟被扩展的类型名,然后才是真正的参数列表。下面是使用示例:

      static class Extensions

      {

      public static int ToInt32(this string source)

      {

      return Int32.Parse(source);

      }

      public static T[] Slice<T>(this T[] source, int index, int count)

      {

      if (index < 0 || count < 0 || index + count > source.Length)

      {

      throw new ArgumentException();

      }

      T[] result = new T[count];

      Array.Copy(source, index, result, 0, count);

      return result;

      }

      }

      class ExtensionMethods : AppRunner.AbstractApplication

      {

      public override void Run()

      {

      string number = "123";

      Console.WriteLine(number.ToInt32());

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

      intArray = intArray.Slice(1, 2);

      foreach (var i in intArray)

      Console.WriteLine(i);

      }

      }

      在上面的示例中,静态的Extensions类中有两个扩展方法,第一个方法是对string类的扩展,它为string类加入了名为ToInt32的方法,该方法没有参数,并返回一个int类型的值,它将完成数字字符向整数的转换。有了这个扩展方法之后,就可对任意string类的对象调用ToInt32方法了,该方法就像其本身定义的一样。

      第二个扩展方法是一个范型方法,它是对所有数组类型的扩展,该方法完成数组的切片操作。

      C# 3.0中的Linq表达式,就是大量运用扩展方法来实现数据查询的。

    第八个特性:Linq查询表达式

      C# 3.0中加入的最为复杂的特性就是Linq查询表达式了,这使我们可直接采用类似于SQL的语法对集合进行查询,这就使我们可以享受到关系数据查询的强大功能。

      Linq查询表达式是建立在多种C# 3.0的新特性之上的,这也是我为什么最后才介绍Linq的原因。下面看一个例子:

      class LinqExpression : AppRunner.AbstractApplication

      {

      public override void Run()

      {

      // 定义匿名数组persons, 并为其赋初值

      var persons = new[] {

      new { Name="Van's", Sex=false, Age=22 },

      new { Name="Martin", Sex=true, Age=30 },

      new { Name="Jerry", Sex=false, Age=24 },

      new { Name="Brog", Sex=false, Age=25 },

      new { Name="Vicky", Sex=true, Age=20 }

      };

      /*

      执行简单Linq查询

      检索所有年龄在24岁以内的人

      查询结果放在results变量中

      results变量的类型与数组persons相同

      */

      var results = from p in persons

      where p.Age <= 24

      select p;

      foreach (var person in results)

      {

      Console.WriteLine

      Console.WriteLine();

      // 定义匿名数组customers, 并为其赋初值

      // 该数组是匿名类型的

      var customers = new[] {

      new {

      Name="Van's", City="China", Orders=new[] {

      new {

      OrderNo=0,

      OrderName="C# Programming Language(Second Edition)",

      OrderDate=new DateTime(2007,9, 5)

      },

      new {

      OrderNo=1,

      OrderName="Head First Design Patterns(Chinese Edition)",

      OrderDate=new DateTime(2007,9,15)

      },

      new {

      OrderNo=2,

      OrderName=Unleashed 2.0(Chinese Edition)",

      OrderDate=new DateTime(2007,09,18)

      },

      new {

      OrderNo=3,

      OrderName="The C++ Programming Langauge(Special Edition)",

      OrderDate=new DateTime(2002, 9, 20)

      }

      }

      },

      new {

      Name="Brog", City="China", Orders=new[] {

      new {

      OrderNo=0,

      OrderName="C# Programming Language(Second Edition)",

      OrderDate=new DateTime(2007, 9, 15)

      }

      }

      },

      new {

      Name="Vicky", City="London", Orders=new[] {

      new { OrderNo=0,

      OrderName="C++ Programming Language(Special Edition)",

      OrderDate=new DateTime(2007, 9, 20)

      }

      }

      }

      };

      /*

      执行多重Linq查询

      检索所在城市为中国, 且订单日期为2007年以后的所有记录

      查询结果是一个匿名类型的数组

      其中包含客户名, 订单号, 订单日期, 订单名四个字段

      */

      var someCustomers = from c in customers

      where c.City == "China"

      from o in c.Orders

      where o.OrderDate.Year >= 2007

      select new o.OrderNo, o.OrderDate, o.OrderName };

      foreach (var customer in someCustomers)

      {

      Console.WriteLine " + customer.OrderName + ", " +

      customer.OrderDate.ToString("D")

      );

      }

      }

      }

      从上面的例子中,我们可以看到Linq查询的强大特性,它允许我们进行简单查询,或者进行更为复杂的多重连接查询。且查询的结果还可以是自定义的匿名类型。

  • 相关阅读:
    Constants and Variables
    随想
    C#基础篇之语言和框架介绍
    Python基础19 实例方法 类方法 静态方法 私有变量 私有方法 属性
    Python基础18 实例变量 类变量 构造方法
    Python基础17 嵌套函数 函数类型和Lambda表达式 三大基础函数 filter() map() reduce()
    Python基础16 函数返回值 作用区域 生成器
    Python基础11 List插入,删除,替换和其他常用方法 insert() remove() pop() reverse() copy() clear() index() count()
    Python基础15 函数的定义 使用关键字参数调用 参数默认值 可变参数
    Python基础14 字典的创建修改访问和遍历 popitem() keys() values() items()
  • 原文地址:https://www.cnblogs.com/jackljf/p/3589000.html
Copyright © 2011-2022 走看看