C# in depth (第八章 用智能的编译器来防错)
8.1 自动实现的属性
公开可见的静态成员通常应该是线程安全的,编译器在这方面帮不上什么忙,得自己去实现
public class InstanceCountingPerson { public string Name { get; private set; } public int Age { get; private set; } private static int InstanceCounter { get; set; } private static readonly object counterLock = new object(); public InstanceCountingPerson(string name, int age) { Name = name; Age = age; lock (counterLock) { InstanceCounter++; } } }
作者见过的使用静态自动属性的唯一情况是,取值方法是公共的,赋值方法是私有的,并且赋值方法只能在类型初始化程序中使用。
(以下代码无法通过编译)
public struct Foo { public int Value { get; private set; } public Foo(int value) { this.Value = value; } }
只有加上this 才可以
public struct Foo { public int Value { get; private set; } public Foo(int value) :this() { this.Value = value; } }
8.2 隐式类型的局部变量
8.2.1 用var声明局部变量
8.2.2 隐式类型的限制
- 被声明的变量是一个局部变量,而不是静态字段和实例字段。
- 变量在声明的同时被初始化;
- 初始化表达式不是方法组,也不是匿名函数。
- 初始化表达式不是null
- 语句中只声明了一个变量。
- 你希望变量拥有的类型是初始化表达式的编译时类型
- 初始化表达式不包含正在声明的变量。
8.2.3 隐式类型的优缺点
8.2.4 建议
8.3 简化的初始化
8.3.1定义示例类型
public class Person { public int Age { get; set; } public string Name { get; set; } List<Person> friends = new List<Person>(); public List<Person> Friends { get { return friends; } } Location home = new Location(); public Location Home { get { return home; } } public Person() { } public Person(string name) { Name = name; } } public class Location { public string Country { get; set; } public string Town { get; set; } }
8.3.2 设置简单属性
Person tom3 =new Person(){ Name ="Tom", Age=9}; Person tom4 =new Person{ Name ="Tom", Age=9}; Person tom5 =new Person("Tom") {Age=9};
C#3.0可以用一个表达式来设置对象的所有属性
Person[] family = new Person[] { new Person{Name ="Holly", Age=36}, new Person{Name ="Jon", Age=36}, new Person{Name ="Tom", Age=9}, new Person{Name ="William", Age=6}, new Person{Name ="Robin", Age=6} }
8.3.3 为嵌入对象设置属性
Person tom = new Person("Tom") { Age =9; Home ={Country ="UK", Town ="Reading"} }
8.3.4 集合初始化程序
1.使用集合初始化程序来创建新集合。
var names = new List<string>{"Holly","Jon","Tom","Robin","Williaam"};
2.在其他对象初始化程序中填充集合
class ObjectInitializer { static void Main() { Person tom = new Person { Name = "Tom", Age = 9, Home = { Town = "Reading", Country = "UK" }, Friends = { new Person { Name = "Alberto" }, new Person("Max"), new Person { Name = "Zak", Age = 7 }, new Person("Ben"), new Person("Alice") { Age = 9, Home = { Town = "Twyford", Country="UK" } } } }; } }
8.3.5 初始化特性的应用
8.4 隐式类型的数组
例如,以下语句编译起来没有任何问题
string[] names = {"Holly", "Jon", "Tom", "Robin", "William" };
但这种写法不适用于参数:
MyMethod(("Holly","Jon","Tom","Robin","William"); 这种写法无法通过编译。
需要写成这样:
MyMethod(new[]("Holly","Jon","Tom","Robin","William")));
8.5 匿名类型
如果分开来看,隐式类型,对象和组合初始化程序以及隐士数组类型均有或大或小的用处。然而它们也可以组合起来使用,从而服务于一个更高的目标,也就是本章最后要讲述的一个特性:匿名类型。而匿名类型又服务员一个更高的目标:LINQ
8.5.1 第一次邂逅匿名类型
class FirstAnonymousType { static void Main() { var tom = new { Name = "Tom", Age = 9 }; var holly = new { Name = "Holly", Age = 37 }; var jon = new { Name = "Jon", Age = 36 }; Console.WriteLine("{0} is {1} years old", jon.Name, jon.Age); } }
class AnonymousTypeInArray { static void Main() { var family = new[] { new { Name = "Holly", Age = 37 }, new { Name = "Jon", Age = 36 }, new { Name = "Tom", Age = 9 }, new { Name = "Robin", Age = 6 }, new { Name = "William", Age = 6 } }; int totalAge = 0; foreach (var person in family) { totalAge += person.Age; } Console.WriteLine("Total age: {0}", totalAge); } }
8.5.2 匿名类型的成员
匿名类型包含以下成员:
- 一个获取所有初始值的构造函数。参数的顺序和它们在匿名对象初始化程序中的顺序一样,名称和类型也一样;
- 公有的只读属性
- 属性的私有只读字段
- 重写的Equals,GetHashCode和ToString。
8.5.3 投影初始化程序
class Projection { static void Main() { List<Person> family = new List<Person> { new Person { Name="Holly", Age=37 }, new Person { Name="Jon", Age=36 }, new Person { Name="Tom", Age=9 }, new Person { Name="Robin", Age=6 }, new Person { Name="William", Age=6 } }; var converted = family.ConvertAll(delegate(Person person) { return new { person.Name, IsAdult = (person.Age >= 18) }; } ); foreach (var person in converted) { Console.WriteLine("{0} is an adult? {1}", person.Name, person.IsAdult); } } }
8.5.4 重点何在
避免过度的数据积累
匿名类型
为一种进行裁减的数据封装 避免手动编写重复的代码