CLR via C#:屬性

屬性:屬性可以看成是智能字段。具有以下特性:
1.屬性可以使用任何可訪問性修飾符。
2.屬性返回類型和參數類型不能爲void。
3.屬性不能作爲out或者ref參數傳遞。
4.C#提供get(元數據爲get_屬性名)訪問器函數用來獲取字段值;提供set(元數據爲set_屬性名)訪問器函數用來修改字段值;提供屬性函數用來包含get和set訪問器函數。開發人員在屬性函數中至少要實現get和set當中一個訪問器函數。
5.訪問器函數的可訪問性修飾符默認跟屬性函數的可訪問性修飾符一樣。只有同時存在get和set訪問器函數時,才能對其中一個訪問器函數使用比屬性函數的可訪問性修飾符的限制性還要大的可訪問性修飾符。
6.C#中不支持泛型屬性訪問器函數,因爲支持的話就有可能改變對象的行爲,而如果要改變對象行爲的話,最好用方法而非屬性。
7.訪問器函數中操作的字段稱爲支持字段。通常將支持字段設置成私有的,從而防止外界修改造成未知異常。
8.當按照使用字段的方式來使用屬性時,編譯器會根據託管程序集中屬性定義項數據信息找到對應的get或者set訪問器函數。
9.set訪問器函數中包含一個對支持字段進行賦值的隱藏value參數。
10.自動實現屬性指的是屬性函數中必須包含“get;”且C#自動爲程序員生成一個私有字段(字段名爲"<屬性名>k__BackingField")以及一個get訪問器函數來操作該私有字段;如果屬性函數中還包含"set;"的話,C#還會生成一個set訪問器函數來操作該私有字段。在需要字段聲明時初始化以及字段序列化的情況下不要使用自動實現屬性這個功能。
11.由於線程同步或者MashaByRefObject(用於遠程訪問)派生類中使用屬性可能花較長的時間執行,從而造成程序終止,所以不建議在這種情況下使用屬性。

無參屬性:包含上面屬性特性外,還具有以下特性:
1.get訪問器函數不接收參數;set訪問器函數接收一個隱藏的value參數。
2.不支持重載,也就是不能有同名屬性。
3.屬性可以應用於靜態屬性,實例屬性,抽象屬性,虛屬性。

有參屬性: 包含上面屬性特性外,還具有以下特性:
1.get訪問器函數接收一個或多個參數;set訪問器函數接收兩個或多個參數(包含隱藏的value參數)。
2.在C#中屬性名有且只有一個,要麼是默認的Item,要麼是IndexerNameAttribute定製特性指定的屬性名。不論哪種屬性名,在代碼中都是this。
3.在VB中屬性名可以有多個,開發人員必須用DefaultMemberAttribute定製特性來標識其他編程語言(如C#)唯一能訪問的屬性名。
4.C#以數組風格的語法來公開參數列表(不包含隱藏的value參數),如"this[int a, string b, float c, …]"。其中"實例對象[int值,string值,float值, …]"會調用get訪問器函數;"實例對象[int值,string值,float值, …]=value"會調用set訪問器函數。
5.支持重載,只要參數列表不同即可。
6.屬性可以應用於實例屬性,抽象屬性,虛屬性。
7.JIT編譯器在運行時會對簡單的get和set訪問器函數進行內聯操作,從而提高屬性的執行效率。

對象初始化器:指的是調用實例構造函數創建對象並設置對象的一些公共屬性或者字段。具有以下特性:
1>.當調用的是無參實例構造函數時,"()"可以省略掉。
2>.當屬性類型是非集合類型的話,初始化是一種替換操作(也就是調用屬性的set訪問器函數來替換關聯字段的值)。代碼如下所示:

String str = new Employee() { Name = "zjz", Age = 18 }.ToString().ToUpper()

等價於:

String str = new Employee { Name = "zjz", Age = 18 }.ToString().ToUpper()

等價於

Employee e = new Employee();
e.Name = "zjz";
e.Age = 18
String str = e.ToString().ToUpper();

3>.當屬性是集合類型(也就是實現了IEnumerable或者IEnumerable接口)的話,初始化是一種相加操作(也就是先調用屬性的get訪問器函數來獲取關聯的集合字段;然後調用集合字段的Add函數來添加值)。代碼如下所示:

public sealed class ClassRoom
{
	private List<string> m_students = new List<string>();
	// 集合類型的屬性
	public List<string> Students
	{
		get
		{
			return m_students;
		}
	}
}

ClassRoom classroom = new ClassRoom() { Students = { "zjz", "yy"} };
等價於:
```csharp
ClassRoom classroom = new ClassRoom { Students = { "zjz", "yy"} };

等價於

ClassRoom classroom = new ClassRoom();
classroom.Students.Add("zjz");
classroom.Students.Add("yy");

匿名類型:指的是new關鍵字後面不指定具體類型,經常與LINQ配合使用。具有以下特性:
1.表達式格式爲:

var o = new { p1=e1, ..., pn=en };

2.編譯器生成爲:

[CompilerGenerated]
internal sealed class <>f__AnonymousType0<...>: Object
{
	private readonly t1 f1;
	public t1 p1
	{
		get
		{
			return f1;
		}
	}
	...
	private readonly tn fn;
	public tn pn
	{
		get
		{
			return fn;
		}
	}
	
	public <>f__AnonymousType0<...>(t1 e1, ..., tn en)
	{
		f1=e1;
		...
		fn=en
	}
	
    public override Boolean Equals(Object value)
    {
    	// 任何一個字段不同就返回false,否則就返回true
    }
     
	public override Int32 GetHashCode()
	{
		// 返回根據每個字段的哈希碼生成的一個哈希碼
	}

	public override String ToString()
	{
		// 返回以"屬性名=值"對的以逗號分隔的列表
	}
}

3.編譯器執行流程爲:
1>.推斷每個表達式的類型並創建推斷類型的私有字段。
2>.爲每個私有字段生成公共只讀屬性,從而防止對象哈希碼發生變化。
3>.創建一個實例構造函數來接收所有表達式,然後在該函數內部用表達式的值來初始化同表達式類型的私有字段。
4>.重寫Object類型的Equals和GetHashCode函數,從而可以將匿名類型對象放入到哈希表集合中。
5>.重寫Object類型的ToString函數來幫助開發人員進行調試。
4.當表達式使用局部變量時,推斷的屬性就等價於該局部變量。如下所示:

String Name = "zjz";
Int32 Age = 20
var o = new { Name, Age }

等價於表達式

var o = new { Name="zjz", Age=20 }

5.當存在多個相同結構(也就是匿名類型中每個屬性具有相同的順序,名稱和類型)時,編譯器也只生成一個匿名類型。
6.匿名類型不能在函數外面使用,也不能在函數參數和返回結果處使用。

元組類型:由.NET提供的一種最多存儲8個元素的類型,其結構跟匿名類型相似。具有以下特性:
1>.元祖中前7個屬性的名字叫做Item#(#代表數字),第8個屬性名字叫做Rest;每個私有字段的名字都是由對應的屬性自動生成。所以開發人員應該寫好註釋來表明每個屬性的具體含義是什麼,從而方便使用和後期維護。
2.元祖中的屬性都是公有隻讀類型,不允許外界改變元祖對象的哈希碼。
3.元祖中第8個屬性類型是包含一個任意元素的Tuple類型。

ExpandoObject類型:等價於一個Dictionary<String, Object>字典類型,允許開發人員在運行時任意設置字典成員。代碼如下所示:

// 運行時創建ExpandoObject對象
dynamic o = new ExpandoObject()
o.x = 6;
o.y = "zjz";
o.z = 20
// 運行時訪問ExpandoObject對象
foreach(var v in (IDictionary<String, Object>)o)
{
	Console.WriteLine("Key={0}, Value={1}", v.Key, v.Value);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章