对象初始化器
对象任何可以访问的字段/属性在构建之后,可通过对象初始化器直接为其进行设定值
public class Bunny
{
public string Name;
public bool LikesCarrots;
public bool LikesHumans;
public Bunny()
{ }
public Bunny(string n) { Name = n; }
}
public class Test
{
public static void Main()
{
Bunny b1 = new Bunny { Name = "bo" };
Bunny b2 = new Bunny("bo") { LikesCarrots = true, LikesHumans = false };
}
}
对象初始化器 VS 可选参数
如果不使用初始化器,上例中的构造函数也可以使用可选参数:
public class Bunny
{
public string Name;
public bool LikesCarrots;
public bool LikesHumans;
public Bunny(string n, bool likesCarrots = false, bool likesHumans = false)
{
Name = n;
LikesCarrots = likesCarrots;
LikesHumans = likesHumans;
}
}
public class Test
{
public static void Main()
{
Bunny b2 = new Bunny(n: "Bo", likesCarrots: false);
}
}
可选参数方法
优点:可以让Bunny类的字段/属性只读
缺点:每个可选参数的值都被嵌入到了Calling site,C#会把构造函数的调用翻译成:
Bunny b2 = new Bunny("Bo", false);
THIS 引用
this引用指的是实例的本身
public class Panda
{
public Panda Mate;
public void Marry(Panda partner)
{
Mate = partner;
partner.Mate = this;
}
}
this引用可以让你把字段与本地变量或参数区分开
只有class/struct的非静态成员菜可以使用this
public class test
{
string name;
public test(string name)
{
this.name = name;
}
}
属性 PROPERTYIES
从外面来看,属性和字段很像。但从内部看,属性含义逻辑,就像方法一样
Stock stock = new Stock();
public void Main()
{
stock.CurremtPrice = 30; //使用起来和字段没有什么区别
stock.CurremtPrice = -3;
}
属性的声明
属性的声明和字段的声明很像,但多了一个get set块
public class Stock
{
decimal curremtPrice;
public decimal CurremtPrice
{
get
{
return curremtPrice;
}
set
{
curremtPrice = value;
}
}
}
属性的GET SET
get/set代表属性额访问器
get访问器会在属性被读取的时候运行,必须返回一个该属性类型的值
set访问器会把属性被赋值的时候运行,有一个隐式的该类型的参数value,通常你会把value付给一个私有字段 例子
属性与字段的区别
尽管属性的访问方式与字段的访问方式相同,但不同之处在于,属性赋予了实现者对获取和赋值的完全控制权。这种控制允许实现者选择任意所需的内部表示,不同属性的使用者公开其内部实现细节。
只读和计算的属性
如果属性只有get就是只读反之只写。
幕后字段value
EXPRESSION-BODIED 属性
从C#6开始,你可以使用Expression-bodied形式来表示只读属性
public decimal Worth => currentPrice * sharesOwned;
//C#7,允许set访问器也可以使用该形式
public decimal Worth
{
get => currentPrice * sharesOwned;
set => sharesOwned = value / currentPrice;
}
//其本质上还是和之前一样,只是写法改变相当于语法糖,编译器编译的时候还是会自动携程之前那样的形式。
自动属性
属性最常见的一种实践就是:getter和setter只是对private field进行简单直接的读写
自动属性声明就是告诉编译器来提供这种实现
public decimal Worth { get; set; }
原理同上
编译器会自动生成一个私有的幕后字段,其名称不可引用(由编译器生成)
set访问器也可以是private或protected
属性初始化器
从C#6开始,你可以为自动属性添加属性初始化器
public decimal Worth { get; set; } = 123m;
只读同理。(只读自动属性也可以在构造函数里被赋值)
也可以对访问器设置访问级别private..
索引器
索引器提供了一种可以访问封装了列表值或字典值的class/struct的元素的一种自然的语法。
string s = "Hello";
System.Console.WriteLine(s[0]);
语法很像使用数组时用的语法,但是这里的索引参数可以使任何类型的
索引器和属性拥有同样的修饰符
可以按照下列方式使用null条件操作符
string s = null;
System.Console.WriteLine(s?[0]);
实现索引器
需要定义一个this属性,并通过中括号指定参数。
class syq
{
public string[] Str = "Hello World!".Split();
public string this[int index]
{
get { return Str[index]; }
set { Str[index] = value; }
}
}
使用的话,类似于数组
多个索引器
一个类型可以声明多个索引器,他们的参数类型可以不同
一个索引器可以有多个参数
public string this[int index, string strIndex]
{
get { ...; }
set { ...; }
}
只读索引器
如果不写set访问器,俺么这个索引器就是只读的。
在C#6以后,也可以使用Expression-bodied语法
public string this[int index] => Str[index];
CLR索引器的实现
索引器在内部会编译成get_Item或set_Item方法
public string get_Item(int wordNum){..}
public string set_Item(int wordNum,string value){..}