在LINQ 中, 用到了很多.NET Framework 3.5 中的新特性,有了这些特性,才使LINQ 的到很好的实现,这些新特性包括匿名类型、隐式类型化局部变量、对象初始化器、自动属性和集合初始化 器。下面就来详细介绍一下这些特性。
1. 匿名类型
匿名类型,顾名思义就是没有名称或者不用定义名称的类型。编译器会自动生成类型的名称和类型中的属 性。例如:
using System;
// 匿名 类型演示 namespace MyConsoleApplication { class Program { static void Main(string [] args) { var myClass = new { Name = "MyClass" , Age = 20 }; Console .WriteLine(string .Format("Name:{0} | Age:{1}" , myClass.Name, myClass.Age.ToString())); Console .Read(); } } }
结果显示: Name:MyClass | Age:20 |
反编译后的 IL 代码如下:
可以看到,系统自动生成的类和其中的字段、属性。需要注意的是,匿名类型中的属性是只读属性,只能 在匿名类型定义时定义并赋值。
2. 隐式类型化局部变量
这个隐式类型化局部变量,就是之前多次出现的使用var 关 键字定义的变量。看到var 的第一个反应就是javascript 里 面的var 关键字。但C# 毕竟是强类型语 言,var 关键字的作用,只是在声明变量时不用写明变量的类型,但是在编译器编译时,还是会自动推 断变量的类型,所以变量在定义后,还是无法更改类型的。
P.S. .NET Framework 3.5 编译器的类型推断功能已经不是一般 的强大了,像 隐式类型化局部变量、Lambda 表 达式,都用到了类型推断。
需要注意的是,隐式类型化局部变量必须在声明时赋值,并且不能赋值为 null 。
3. 对象初始化器和自动属性
这两个特性在之前都已经使用过。对象初始化器就是允许在实例化对象时,直接对对象中的可写属性进行赋 值。自动属性可以不定义字段,只定义属性的读写特性和访问级别,由编译器在编译时自动生成字段。如下:
using System;
// 对象 初始化器和自动属性的演示 namespace MyConsoleApplication { class Program { static void Main(string [] args) { // 对象初始化器 MyClass myClass = new MyClass { Address = "BeiJing" , Age = 20, Name = "MyClass" }; } }
class MyClass { // 自动属性,定义了set 的可访问性 public string Name { get ; internal set ; }
public int Age { set ; get ; }
public string Address { set ; private get ; } } } |
自动属性的缺点有:无法自定义属性中的操作;在程序中不能访问字段(因为根本就没有定义字段,字段是 由编译器生成的)。自动属性只起到一个数据访问接口的作用,并且自动属性必须定义get 和set 访问器。
4. 集合初始化器
集合初始化器的作用就是在集合对象实例化时,自动将所需元素添加至集合中。例如:
using System; using System.Collections.Generic;
// 集合 初始化器的演示 namespace MyConsoleApplication { class Program { static void Main(string [] args) { // 集合初始化器 IList <MyClass > myList = new List <MyClass >{ new MyClass { Address = "BeiJing" , Age = 20, Name = "MyClass" }, new MyClass { Address = "ShangHai" , Age = 25, Name = "MyClass2" }, new MyClass { Address = "TianJin" , Age = 19, Name = "MyClass3" } }; Console .WriteLine(myList.Count.ToString()); Console .Read(); } }
class MyClass { // 自动属性,定义了set 的可访问性 public string Name { get ; internal set ; }
public int Age { set ; get ; }
public string Address { set ; private get ; } } }
结果显示: 3 |
——————— 必定出现的分割线 ————————
再说扩展方法:
扩展方法可以起到削减类的职责的作用,类中只定义必要的数据结构(字段和属性)、构造器(终结器)、 转换器,然后利用扩展方法,为类添加适当的职责。这样可以减少子类的创建。
个人觉得这种方法不利于进行面向接口的编程,扩展方法之所以叫扩展方法,说明她的主要功能还是在于 “扩展”而不是“定义”或“规定”。但是在一些接口或者基类上定义的扩展方法,还是可以起到很重要的作用的。