當我們從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程序員實際編程過程中,還是面向過程編程,這的確是一種避免不了的事實,小型企業利潤還是首要的,軟件能用就行。