深入理解C#(十五)

*第八章(C# 3:用智能的编译器来防错)

自动实现的属性

简化普通属性的代码

普通属性:可读/可写并将值存储到一个非常直观的私有变量中的属性。

1
public string Name{get;set;}

仍然可以为取值和赋值方法指定不同的访问权限。

静态自动属性:取值方法是共有的,赋值方法是私有的,且赋值方法只能在类型初始化程序中使用。

定义struct时,使用自动属性,需要显式地调用无参构造函数

1
2
3
4
5
6
7
8
public struct Foo
{
public int Value{get;private set;}
public Foo(int value):this()
{
this.Value=value;
}
}

自动属性仍有几个小问题:

  1. 没办法在声明时,设定初始的默认值
  2. 没法把它们设定成真正的只读属性(使用私有赋值方法来解决)

隐式类型的局部变量

使用var声明局部变量

var并没有把C#变成动态类型或者弱类型的语言,只是类型由编译器推断

编译器获取初始化表达式在编译时的类型,并使变量也具有那种类型。

隐式类型的限制

只有在一下情况能使用:

  • 局部变量,不是静态字段和实例字段
  • 声明的同时被初始化
  • 初始化表达式不是方法组和匿名函数
  • 初始化表达式不是null
  • 语句中之声明了一个变量
  • 初始化表达式不包含正在声明的变量

对于第三点,显示声明变量是可以的,如:
var starter = (ThreadStart)delegate(){ Console.WriteLine();}
对于null也可以做强制类型转换,但是无意义。

最常见应用:用方法调用的结果来初始化一个变量。

隐式类型的优缺点

优点:增强可读性,改变代码重心
缺点:类型不明确

简化的初始化

定义示例类型

new Person{Name="Jon",Age=36}

为嵌入对象设置属性

1
2
3
4
Person tom=new Person("Tom"){
Age=9,
Home={Country="UK",Town="Reading"}
};

集合初始化程序

  1. 使用集合初始化程序来创建新集合
    List<string> names=new List{ "Holly","Jon","Tom"};
    任何实现了IEnumerable类型,只要它为初始化列表中出现的每个元素都提供了一个恰当的公共的Add方法,就可以使用这个特性。
  2. 在其他对象初始化程序中填充集合

隐式类型的数组

对于void MyMethod(string[] names)
C#3 这样使用:

MyMethod(new[] {"Holly","Jon","Tom"});

匿名类型

实例:使用匿名类型,填充数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);

family中所有人具有相同的类型,否则编译器无法推断出何时类型。

匿名类型的成员

  • 一个获取所有初始值的构造函数
  • 共有的只读属性
  • 属性的私有只读字段
  • 重写的Equals、GethashCode和ToString

投影初始化程序

实际使用时,往往希望从别的对象复制属性用以新建一个新的对象。 例如:new { Name=person.Name,IsAdult=(person.Age>=18)}
C# 3支持一种简化的语法:如果不指定属性名称,而只指定用于求指的表达式,它会使用表达式的最后一个部分作为名称,前提是它只是一个简单字段或属性。

应用:new { person.Name, IsAdult=(Person.Age>=18)}