C#3.0语言详解之基本的语言增强
对象和集合初始化器
1、对象初始化器
在C# 3.0出现之前,如果想在构造一个对象的时候对其成员进行初始化,只有通过调用带参数的构造器来完成。如果一个类型仅提供了无参构造器(默认构造器)或构造器接受的参数和对象的公共属性没有太大关系,对对象的初始化就只能通过两个步骤来完成:首先是声明一个对象,然后对其公共属性进行赋值。
C# 3.0引入了对象初始化器的语言构造,可以在声明对象的时候对其公共可读写属性进行赋值。例如我们有这样一个类型:
class Book
{
private string m_name;
private string m_isbn;
private float m_price;
public string Name { get { return m_name; } set { m_name = value; } }
public string Isbn { get { return m_isbn; } set { m_isbn = value; } }
public float Price { get { return m_price; } set { m_price = value; } }
}
那么,我们就可以用下面的简单方式来初始化Book类的对象:
var firstBook = new Book
{
Name = "The First Sample Book",
Isbn = "1-111-11111-1",
Price = 88.0f
};
var secondBook = new Book
{
Name = "The Second Sample Book",
Price = 25.0f,
Isbn = "2-222-22222-2"
};
也就是说,只要在对象声明语句的末尾添加一对花括号,并在其中对每个属性进行赋值即可。并且我们可以看到,第二个声明中对属性的赋值语句的顺序与 Book类中属性定义的顺序并不相同,但这完全是符合语法规则的,只要明确指定了要赋值的属性名字即可。另外,也可以只对一部的属性进行赋值,如只对 Isbn进行赋值,而在稍后通过查询等手段为Name和Price属性赋值。甚至可以保留一个空的属性赋值列表,这时每个属性都被赋以相应类型的默认值。
实际上,对象初始化器完成的工作还是我们以前要完成的那两步,只不过由编译器代劳了,例如上面对firstBook的声明将被编译器翻译为形如下面的代码,之后才进行进一步的编译:
var firstBook = new Book;
firstBook.Name = "The First Sample Book";
firstBook.Isbn = "1-111-11111-1";
firstBook.Price = 88.0f;
2、集合初始化器
我们知道,在C# 1.x和C# 2.0中,可以通过一个包含在花括号之间的值列表来初始化一个刚刚声明的数组,如:
int[] intArray = new int[] { 1, 2, 3};
然而,对于和数组有着类似功能的其他集合(如List)就不能享受这种方便的语法了,只能在声明完集合对象后将值一个一个地添加到集合中。而C# 3.0提出了集合初始化器的语言构造,可以用初始化数组的便捷语法来初始化任何一个实现了ICollection<T>接口的对象。这里以 C# 2.0中引入的著名的泛型类型List<T>为例:
var intList = new List<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("A list of int:");
foreach(var i in intList)
Console.WriteLine("{0} ", i);
运行上面这段代码,可以得到下面的结果:
A list of int:
1
2
3
4
5
前面提到了,这种语法可以用来初始化任何实现了ICollection<T>接口的对象,这实际上是编译器的功劳。编译器针对这种语法自动生成了循环调用ICollection.Add方法的代码,将列表中的值一个一个地添加到正在声明的集合中。例如:
var intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
intList.Add(4);
intList.Add(5);
另外,也必须是实现了ICollection<T>的对象才能用这种语法进行初始化,其他具备Add方法但未实现ICollection<T>的对象不能这样初始化;同时在声明中还必须明确指定类型参数T所代表的实际类型。