Chapter10 属性
无参属性
面向对象设计和编程的重要原则数据封装,它意味着类型的字段永远不应该公开,因为这样很容易写出不恰当使用字段的代码,从而破坏对象的状态。
由于很多原因,强烈建议将所有字段都设为private,然后公开一个针对获取或设置状态信息的方法,封装了字段访问的方法通常称为:访问器(accessor)
这样会增加代码量和用户必须调用访问器来修改或获取值。
然后就出现了属性(smart field)
然后又出现了自动实现的属性(Automatically Implemented Property)AIP,public string Name {get; set; }
使用AIP的注意几点:
- 必须在每个构造器方法中显式初始化每个AIP
- 如果需要序列化和反序列化类型,都不要使用AIP功能
- 不能在AIP的get和set方法上添加一个断点
合理定义属性:
属性看起来与字段相似,但本质上是方法。
字段与属性区别:
- 属性可以是只读或只写,字段却总是可读和可写(标记readonly的字段仅在构造器中可写)
- 属性不能作为out或ref参数传给方法,字段却可以。
- 属性方法可能花费较长时间执行,字段的访问则总是立即完成
- 如果需要线程同步,就不应该使用属性,最好使用方法
- 如果类可以被远程访问,优先使用方法而不是属性
- 属性每次返回可能是不同的值,如DateTime.Now;Environment.TickCount
- property方法可能需要额外的内存来返回一个引用,而该引用实际上不是对象状态的一部分,因此改变这个返回值并不会对原有对象生效。
对象和集合初始化器
- Employee e = new Employee { Name = "Jeff", Age = 45 };
- var table = new Dictionary<string, int> {{ "Jeffrey", 1 }, { "Kristin", 2 }, { "Aidan", 3 }, { "Grant", 4 }};
匿名类型
- var o1=new { Name="Jeff",Year=1964};
- 编译器对上面一行所做的事情:
- 推断每个表达式的类型,创建类型的私有字段,为每个字段创建公共只读属性,并创建一个构造器来接受所有表达式初始化,编译器还会重写Object的Equals、GetHashCode和ToString方法
有参数性
索引器,C#(this[...]),带参数的属性至少要有一个参数,可以是除void的任何类型
C#不支持静态indexer属性,虽然CLR支持静态参数化属性
System.Runtime.CompilerServices.IndexerNameAttribute重命名indexer名称,但是IndexerNameAttribute不是CLI和C#ECMA标准的一部分;
C#可以将indexer看作是[]操作符重载
System.Reflection.DefaultMemberAttribute,选择一个参数化的属性作为缺省属性