當我們從C語言接觸編程開始,一旦定義一個類,我們必然會給這個類定義許多資料成員。然後C#本身卻正在極力改變這樣一個事實,從各種伺服器控制項編寫你應該可以看出,net對屬性的支援遠遠大於對成員的支援。從我的部落格自訂學習控制項(一)中你可以看見,當我們自己書寫自訂控制項時,我們對控制項類的定義幾乎是屬性,而不是資料成員。
屬性本質上為兩個函數,get and set函數,而C#的特殊文法一直讓我們可以像訪問成員一樣訪問它。因此我們可以在屬性的設計上添加更多靈活地內容。get函數讓我們返回一個值,而set函數讓我們設定返回的值。
如下,我們定義一個Person類,代碼如下(小提示,當我們寫了欄位後,如何快速寫出其屬性呢,選擇 name ,然後ctrl+r+e,點擊確定,就快速寫出屬性了)
圖1.1
public class Person { private string name; public string Name { get { return name; } set { name = value; } } }
當一個類不寫任何存取修飾詞時,預設的存取權限是internal,而不是所謂的sealed。 這個類的屬性Name既有讀也有寫屬性。為什麼說get和set是兩個函數呢。當然也有人這樣寫
public string Name{ get { returen this.name; } set { this.name=value; }}
雖然這樣寫比上面明了許多,但仍不夠明確。其實,查看IL,可以知道,IL為我們產生了get_Name與set_Name兩個函數,如下。
圖 1.2
那麼,屬性和欄位的區別是什麼呢?個人理解,屬性就是對欄位的封裝。因為微軟告訴我們了,圖1.1就可以看到。
使用屬性充分體現了對象的封裝性:不直接操作類的資料內容,而是通過訪問器進行訪問,即藉助於get和set對屬性的值進行讀寫;另一方面還可以對資料的訪問屬性進行控制。舉個例子,如果你不希望某個欄位的值大於5,就可以在屬性的set函數中,此進行邏輯控制。那麼這比直接對欄位進行控制有什麼好處呢?個人理解,如果你希望重用某個類,而不是僅僅用一兩次(雖然我暫時用的比較少,但是在工作中卻用到過,比如用ascx檔案,往這個使用者控制項中某個屬性傳遞參數)。
其實,屬性似乎還有這樣一個作用,可以綁定資料,這一定我們可以從TextBox這些控制項中可以看出來,而欄位卻不能綁定資料,但是可以儲存資料。
我們經常聽到抽象類別,抽象屬性你卻可能極少聽到。沒錯,有抽象屬性,卻沒有抽象欄位。有了抽象屬性,這為我們設計出相容性更強,擴充性更強的類提供了好的解決方案。請看下面一個例子。
public abstract class Sharp { private string name; public string SharpName { get { return name; } set { name = value; } } public Sharp(string s) { SharpName = s; } public abstract double Area { get; } public override string ToString() { return SharpName + " Area=" + string.Format("{0:F2}", Area); }
在這個類中,我們有一個抽象屬性面積Area,唯讀屬性。然後有個私人欄位name(用於記錄該形狀的名稱),一個公用屬性,還重寫了ToString()函數,返回該圖形的面積。
下面兩個類,一個正方形,一個圓形,繼承了該圖形形狀類,代碼如下
public class Square:Sharp { private int side; public Square(int side, string SharpName) : base(SharpName) { this.side = side; } public override double Area { get { return side * side; } } } public class Circle:Sharp { private int radius; public Circle(int radius, string SharpName) : base(SharpName) { this.radius = radius; } public override double Area { get { return radius * radius * System.Math.PI; } }
在這兩個類中,我們重寫了抽象屬性Area,分別計算正方形和圓形的面積。我們只需要往該類中傳入該圖形的特有的屬性如邊長,半徑,就可得到面積。
Sharp[] shapes = { new Square(5,"Square"), new Circle(3,"Circle") }; foreach (Sharp item in shapes) { Console.WriteLine(item); }
這種代碼的書寫簡便靈敏,減少代碼數量,有一點點小小的設計模式的味道。
公用成員與屬性雖然調用的文法都是 對象名.Area或對象名.MyName,但是IL語言上卻是不通的,屬性調用的是get_Area()方法,而成員調用的則是這個字串所儲存的資料。
屬性和資料成員這兩個東西,說白了就是屬性封裝了資料成員,讓我們瞭解物件導向的含義。雖然大多數.net程式員實際編程過程中,還是面向過程編程,這的確是一種避免不了的事實,小型企業利潤還是首要的,軟體能用就行。