屬性Property與欄位Field,傻傻分不清楚
今天看到網路上的一篇文章,一個C#的初心者在介紹一些功能時,把屬性跟欄位的意思完全搞錯了,因此在此記錄一下屬性Property與欄位Field真正的用意。
以下是相關的說明:
欄位(Field)
對於物件封裝來說,沒有什麼比保護好你物件裡面的相關參數來的更重要的了,而欄位往往就是用於此,也就是它通常被用來暫存某些狀態或運算結果,但你不會想要把這個數值公開在外,讓外部物件操控者直接去存取。它會長的像下列的樣子:
public class TEST
{
// public field
public string name;
// private field
private DateTime _birthday;
}
從上面的例子我們可以發現,在物件導向裡大家約定成俗的使用方式,有加底線的大概都是封裝考量下的私有變數,如果沒有底線的變數大都屬於公開的,這樣的寫法叫欄位。
另外可能又會有人說,等等,你說欄位大都是用於封裝用,不能讓人家直接存取,那為何上例的name變數是public呢?這豈不是可以讓人家直接存取嗎?沒錯,答案是「Yes,可以直接存取。」,原因是因為這個物件的撰寫者覺得這個讓外界存取是可以的,因此「不進行封裝」。
※補充:欄位在Java的世界裡面被稱為「資料成員」。
屬性(Property)
屬性的用法就是在私有欄位之間,當作一個中間層,用來限制某些讀取,亦或用來限制某些寫入,例如上例來說,有人試圖寫入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#就可以支援另外一種叫「自動實作屬性」的寫法了。
自動屬性實作(Auto-Implemented Properties)
自動屬性實作我覺得完全是因應物件關聯對映(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; }
}
延伸閱讀: