对象初始化器

对象任何可以访问的字段/属性在构建之后,可通过对象初始化器直接为其进行设定值

  1. public class Bunny
  2. {
  3. public string Name;
  4. public bool LikesCarrots;
  5. public bool LikesHumans;
  6. public Bunny()
  7. { }
  8. public Bunny(string n) { Name = n; }
  9. }
  10. public class Test
  11. {
  12. public static void Main()
  13. {
  14. Bunny b1 = new Bunny { Name = "bo" };
  15. Bunny b2 = new Bunny("bo") { LikesCarrots = true, LikesHumans = false };
  16. }
  17. }

对象初始化器 VS 可选参数

如果不使用初始化器,上例中的构造函数也可以使用可选参数:

  1. public class Bunny
  2. {
  3. public string Name;
  4. public bool LikesCarrots;
  5. public bool LikesHumans;
  6. public Bunny(string n, bool likesCarrots = false, bool likesHumans = false)
  7. {
  8. Name = n;
  9. LikesCarrots = likesCarrots;
  10. LikesHumans = likesHumans;
  11. }
  12. }
  13. public class Test
  14. {
  15. public static void Main()
  16. {
  17. Bunny b2 = new Bunny(n: "Bo", likesCarrots: false);
  18. }
  19. }

可选参数方法
优点:可以让Bunny类的字段/属性只读
缺点:每个可选参数的值都被嵌入到了Calling site,C#会把构造函数的调用翻译成:

  1. Bunny b2 = new Bunny("Bo", false);

THIS 引用

this引用指的是实例的本身

  1. public class Panda
  2. {
  3. public Panda Mate;
  4. public void Marry(Panda partner)
  5. {
  6. Mate = partner;
  7. partner.Mate = this;
  8. }
  9. }

this引用可以让你把字段与本地变量或参数区分开
只有class/struct的非静态成员菜可以使用this

  1. public class test
  2. {
  3. string name;
  4. public test(string name)
  5. {
  6. this.name = name;
  7. }
  8. }

属性 PROPERTYIES

从外面来看,属性和字段很像。但从内部看,属性含义逻辑,就像方法一样

  1. Stock stock = new Stock();
  2. public void Main()
  3. {
  4. stock.CurremtPrice = 30; //使用起来和字段没有什么区别
  5. stock.CurremtPrice = -3;
  6. }

属性的声明

属性的声明和字段的声明很像,但多了一个get set块

  1. public class Stock
  2. {
  3. decimal curremtPrice;
  4. public decimal CurremtPrice
  5. {
  6. get
  7. {
  8. return curremtPrice;
  9. }
  10. set
  11. {
  12. curremtPrice = value;
  13. }
  14. }
  15. }

属性的GET SET

get/set代表属性额访问器
get访问器会在属性被读取的时候运行,必须返回一个该属性类型的值
set访问器会把属性被赋值的时候运行,有一个隐式的该类型的参数value,通常你会把value付给一个私有字段 例子

属性与字段的区别

尽管属性的访问方式与字段的访问方式相同,但不同之处在于,属性赋予了实现者对获取和赋值的完全控制权。这种控制允许实现者选择任意所需的内部表示,不同属性的使用者公开其内部实现细节。

只读和计算的属性

如果属性只有get就是只读反之只写。
幕后字段value

EXPRESSION-BODIED 属性

从C#6开始,你可以使用Expression-bodied形式来表示只读属性

  1. public decimal Worth => currentPrice * sharesOwned;
  2. //C#7,允许set访问器也可以使用该形式
  3. public decimal Worth
  4. {
  5. get => currentPrice * sharesOwned;
  6. set => sharesOwned = value / currentPrice;
  7. }
  8. //其本质上还是和之前一样,只是写法改变相当于语法糖,编译器编译的时候还是会自动携程之前那样的形式。

自动属性

属性最常见的一种实践就是:getter和setter只是对private field进行简单直接的读写
自动属性声明就是告诉编译器来提供这种实现

  1. public decimal Worth { get; set; }

原理同上
编译器会自动生成一个私有的幕后字段,其名称不可引用(由编译器生成)
set访问器也可以是private或protected

属性初始化器

从C#6开始,你可以为自动属性添加属性初始化器

  1. public decimal Worth { get; set; } = 123m;

只读同理。(只读自动属性也可以在构造函数里被赋值)
也可以对访问器设置访问级别private..

索引器

索引器提供了一种可以访问封装了列表值或字典值的class/struct的元素的一种自然的语法。

  1. string s = "Hello";
  2. System.Console.WriteLine(s[0]);

语法很像使用数组时用的语法,但是这里的索引参数可以使任何类型的
索引器和属性拥有同样的修饰符
可以按照下列方式使用null条件操作符

  1. string s = null;
  2. System.Console.WriteLine(s?[0]);

实现索引器

需要定义一个this属性,并通过中括号指定参数。

  1. class syq
  2. {
  3. public string[] Str = "Hello World!".Split();
  4. public string this[int index]
  5. {
  6. get { return Str[index]; }
  7. set { Str[index] = value; }
  8. }
  9. }

使用的话,类似于数组

多个索引器

一个类型可以声明多个索引器,他们的参数类型可以不同
一个索引器可以有多个参数

  1. public string this[int index, string strIndex]
  2. {
  3. get { ...; }
  4. set { ...; }
  5. }

只读索引器

如果不写set访问器,俺么这个索引器就是只读的。
在C#6以后,也可以使用Expression-bodied语法

  1. public string this[int index] => Str[index];

CLR索引器的实现

索引器在内部会编译成get_Item或set_Item方法

  1. public string get_Item(int wordNum){..}
  2. public string set_Item(int wordNum,string value){..}