今天看到網路上的一篇文章,一個C#的初心者在介紹一些功能時,把屬性跟欄位的意思完全搞錯了,因此在此記錄一下屬性Property與欄位Field真正的用意。
以下是相關的說明:
對於物件封裝來說,沒有什麼比保護好你物件裡面的相關參數來的更重要的了,而欄位往往就是用於此,也就是它通常被用來暫存某些狀態或運算結果,但你不會想要把這個數值公開在外,讓外部物件操控者直接去存取。它會長的像下列的樣子:
public class TEST { // public field public string name; // private field private DateTime _birthday; }
從上面的例子我們可以發現,在物件導向裡大家約定成俗的使用方式,有加底線的大概都是封裝考量下的私有變數,如果沒有底線的變數大都屬於公開的,這樣的寫法叫欄位。
另外可能又會有人說,等等,你說欄位大都是用於封裝用,不能讓人家直接存取,那為何上例的name變數是public呢?這豈不是可以讓人家直接存取嗎?沒錯,答案是「Yes,可以直接存取。」,原因是因為這個物件的撰寫者覺得這個讓外界存取是可以的,因此「不進行封裝」。
※補充:欄位在Java的世界裡面被稱為「資料成員」。
屬性的用法就是在私有欄位之間,當作一個中間層,用來限制某些讀取,亦或用來限制某些寫入,例如上例來說,有人試圖寫入2014/02/31這個日期,你還要讓他寫入嗎?(雖然說以這個例子對照程式碼來說不太洽當,因為System.DateTime就會擋下來了,所以不可能會有2014/02/31這個數據出現。)欄位的使用方式會長的像下列的樣子:
public class TEST { public string name; private DateTime _birthday; public DateTime Birthday { get { return _birthday; } set { if (value.Year > 1900 && value.Year <= DateTime.Today.Year) { _birthday = value; } else { throw new System.Exception("Error Date Formate."); } } } }
欄位跟屬性大概就是這樣用了。另外可能還會有人說,等等,那如果我要全封裝類別欄位,那麼name也幫我示範一下好嗎?沒問題,我們只討論name欄位時,程式碼會長的如下:
public class TEST { private string _name; public string Name { get { return _name; } set { _name = value; } } }
看完上面的程式碼,你對我白眼我覺得是正常的,因為根本脫褲子放屁,所以要嘛回歸到一開始的寫法(直接存取),要嘛就請你將.NET Framework升上3.0,然後你的C#就可以支援另外一種叫「自動實作屬性」的寫法了。
自動屬性實作我覺得完全是因應物件關聯對映(ORM, Object Relational Mapping)而生的偷懶性產物,但是受到大家的喜愛啊。以上面的name情境為例,程式碼會長的像這樣:
//它看起來像欄位,但是它是屬性,請勿誤認 public string Name { get; set; }
※補充:在Java的世界裡面,沒有屬性這種東西,如果要實作某欄位可被存取,那麼你要設計二個「方法成員」來存取它。以上述的程式碼來說,你要設計成下列的蠢樣:
public class TEST { private string _name; public void setName(string cTemp) { _name = cTemp; } public string getName(string cTemp) { return _name; } }
延伸閱讀:
欄位 屬性 Field Property AutoImplementedProperties ObjectRelationalMapping