LINQ学习笔记之三
——其他新特性
在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
|
——————— 必定出现的分割线 ————————
再说扩展方法:
扩展方法可以起到削减类的职责的作用,类中只定义必要的数据结构(字段和属性)、构造器(终结器)、转换器,然后利用扩展方法,为类添加适当的职责。这样可以减少子类的创建。
个人觉得这种方法不利于进行面向接口的编程,扩展方法之所以叫扩展方法,说明她的主要功能还是在于“扩展”而不是“定义”或“规定”。但是在一些接口或者基类上定义的扩展方法,还是可以起到很重要的作用的。