【原文地址】new c# "orcas" language features: automatic properties, object initializers, and collection initializers
【原文发表日期】 thursday, march 08, 2007 11:01 pm
上个星期,我们发布了我们的visual studio和.net框架orcas版三月份的ctp,这是个谁都可以下的免费下载,同时提供vpc镜像(允许你在一个虚拟机里运行它)以及单独的安装文件(注:如果你在运行vista的话,你要确认你只使用vpc版本)。你可以在这里下载。
几个星期前,我曾在博客上讨论过orcas中针对asp.net开发人员的一些重大的改进。如果你还没有读过这个贴子的话,我强烈建议你在这里读一下。我认为你会非常喜欢该帖子讨论的新特性的。
除了那些框架和工具类的精彩新特性外,我认为开发人员(包括所有的.net应用类型的开发人员)会非常喜爱orcas的一件事情是,vb和c#将包含一些新语言特性和改进。这些语言改动将以既微妙又深刻的方式改进我们的开发体验,势将改进效率,减小我们需要键入的代码量。
在下几个星期里,我将试着在博客里讨论几个这些语言的改进之处,示范如何把它们使用在一起,来产生一些非常强有力的结果。
新的c#语言特性:自动属性(automatic properties)
如果你现在是c#开发人员的话,你大概非常习惯编写象下面这个代码片段一样带有基本属性的类型:
public class person {
private string _firstname;
private string _lastname;
private int _age;
public string firstname {
get {
return _firstname;
}
set {
_firstname = value;
}
}
public string lastname {
get {
return _lastname;
}
set {
_lastname = value;
}
}
public int age {
get {
return _age;
}
set {
_age = value;
}
}
}
注意,我们在属性的geter/setter中实际上并没有添加什么逻辑,我们只是将get/set实施到了一个成员变量。我们不禁要问这样一个问题:为什么不直接使用成员变量而使用属性呢?这是因为,向外面呈现公开的成员变量有很多不好的地方。二个最大的问题是:1) 你无法轻易地对成员变量做数据绑定,2) 如果你从类中向外呈现成员变量的话,之后,你不重新编译那些引用老的类的任何程序集,就无法将它们改成属性(譬如,要添加验证逻辑到setter里)。
orcas中发布的新c#编译器通过一个叫“自动属性(automatic properties)”的语言特性提供了一个优雅的方式来使得你的编码更加简洁,同时还保持属性的灵活性。自动属性允许你避免手工声明一个私有成员变量以及编写get/set逻辑,取而代之的是,编译器会自动为你生成一个私有变量和默认的get/set 操作。
譬如,使用自动属性,我现在可以将上面的代码改写成:
public class person {
public string firstname {
get; set;
}
public string lastname {
get; set;
}
public int age {
get; set;
}
}
或者,我想更简明的话,我可以将空白的地方做进一步压缩,象这样:
public class person {
public string firstname { get; set; }
public string lastname { get; set; }
public int age { get; set; }
}
当orcas版中的c#编译器遇上象上面这样的空的get/set属性的话,它会自动为你在类中生成一个私有成员变量,对这个变量实现一个公开的getter 和setter。这么做的好处是,从类-合同(type-contract)的角度来看,这个类跟我们上面第一个有点冗长的实现看上去完全一样,这意味着,不象公开的成员变量,在将来,我可以在我的属性setter实现中添加验证逻辑,而不用对引用我的类的任何外部组件做改动。
bart de smet对使用orcas三月份ctp版中的自动属性时内部发生的情形作了精彩的描述,你可以在这里阅读他的精彩相关帖子。
c#和vb语言的新特性:对象初始化器(object initializers)
.net框架中的类型非常依赖于属性的使用。当生成对象实例和使用新的类型时,写出象下面这样的编码是非常常见的情形:
person person = new person();
person.firstname = "scott";
person.lastname = "guthrie";
person.age = 32;
你有没有想要把这样的编码简化过(也许将其安排在一行上)?使用orcas中的c#和vb语言编译器的话,你现在可以利用一个称为“对象初始化器(object initializers)”的“语法甜头(syntactic sugar)”语言特性来做些简化,将上述代码重写为:
person person = new person { firstname="scott", lastname="guthrie", age=32 };
然后,编译器就会自动地生成合适的属性setter代码,保持跟前面较冗长的代码例子同样的语意。
除了在初始化类时设置简单的属性值外,对象初始化器特性也允许我们设置更复杂的嵌套(nested)属性类型。譬如,假如我们在上面定义的每个person类型也拥有一个属于address类型的叫“address”的属性。我们可以编写下面这样的代码来生成一个新的person对象,同时设置它的属性,象这样:
person person = new person {
firstname = "scott",
lastname = "guthrie"
age = 32,
address = new address {
street = "one microsoft way",
city = "redmond",
state = "wa",
zip = 98052
}
};
bart de smet对使用orcas三月份ctp版中的对象初始化器时内部发生的情形也作了精彩的描述,你可以在这里阅读他的精彩相关帖子。
c#和vb语言的新特性:集合初始化器(collection initializers)
对象初始化器很棒,它极大地简化了把对象添加到集合的做法。譬如,假如我要把三个人加到一个基于泛型的类型为person的list集合中去的话,我可以写下面这样的编码:
list<person> people = new list<person>();
people.add( new person { firstname = "scott", lastname = "guthrie", age = 32 } );
people.add( new person { firstname = "bill", lastname = "gates", age = 50 } );
people.add( new person { firstname = "susanne", lastname = "guthrie", age = 32 } );
对这个例子,跟我使用c# 2.0编译器要输入的代码相比,单独使用新的对象初始化器特性就能省去12行额外的代码。
但orcas版中的c#和vb编译器允许我们更进一步,现在同时支持“集合初始化器(collection initializers)”,这允许我们避免要写多个add语句,省下更多的键盘操作:
list<person> people = new list<person> {
new person { firstname = "scott", lastname = "guthrie", age = 32 },
new person { firstname = "bill", lastname = "gates", age = 50 },
new person { firstname = "susanne", lastname = "guthrie", age = 32 }
};
当编译器遇上上面这样的句法时,它会自动为我们生成象前面的例子一样的集合插入编码。
结语
作为开发人员,我们现在拥有了简明得多的方式来定义对象,对它们初始化,将它们加入集合内。在运行时,其语意,跟今天的较长的版本的语意,是完全一样的(所以你不必担心行为会改变)。但现在你不需输入那么多字符了,你的代码将既干净又简明。
在不远的将来,我将发表更多的博客贴子来讨论orcas版中更多的语言上的改进,包括扩展方法(extension methods),lambdas和匿名类。然后,我将对linq做深入讨论,示范它是如何利用所有这些特性来提供一个非常优雅的方式来查询和与数据交互的。
希望本文对你有所帮助,
scott