屬性(Property) 與欄位(Field) - mrkt 的程式學習筆記

文章推薦指數: 80 %
投票人數:10人

Property:FullDescription為主要資料取得的地方,對外公開;. Field:_FullDescription為物件私有成員,是用來存放屬性的資料。

MSDN - 使用屬性(C# 程式 ... 網頁 首頁 VisualStudio ASP.NETMVC Oraclewith.NET 系統記錄與效能監測 前端開發 範例程式@GitHub 2011年9月22日星期四 屬性(Property)與欄位(Field) 建立類別的時候,往往會遇到這兩個成員:Property以及Field,熟悉物件導向對於物件封裝的人應該是可以區分這兩種成員的差別,但是對於初學者或是對OO不熟悉的人是搞不清楚,明明兩種都是可以去儲存以及取得物件中的資料,但是到底兩者有什麼差別呢?又應該在什麼樣的情況下去使用這兩種成員?所以就看到很多人都是直接在自訂類別中使用Field,這狀況尤其在ASP.NETMVC的ViewModel最多,為什麼要捨Property而就Field呢?因為Filed在Coding時最快、最方便。

反正只要可以存取資料,管他什麼是Property、Field……但是這樣對嗎?讓我們來認識Property與Field的差別。

我們先來看看在MSDN上面對於Property與Field的說明:MSDN-類別屬性、欄位和方法MSDN-屬性程序和欄位:協助您判斷何時使用欄位將資料儲存於類別中,以及何時是使用屬性的較佳時機。

節錄並整理如下:屬性和欄位都可以儲存和擷取物件中的資訊。

它們的相似處讓使用者很難判斷在某個狀況下較適合用哪一個來撰寫程式。

屬性:Property使用屬性程序的時機:您需要控制設定或擷取值的時機和方法。

屬性具有定義妥善且需要加以驗證的值集。

設定值造成可察覺的物件狀態變更,例如IsVisible屬性。

設定屬性造成其他內部變數或其他屬性值的變更。

在設定或擷取屬性前,必須執行一組步驟。

欄位:Field使用欄位的時機:值屬於自我驗證型別。

例如,如果將True或False以外的值指派給Boolean變數,會發生錯誤或自動資料轉換。

資料型別所支援範圍內的任何值為有效值。

Single或Double型別的許多屬性都適用。

屬性為String資料型別,且字串大小或字串值沒有限制。

在MSDN的這一篇文件中「HOWTO:將欄位和屬性加入至類別」有說到:您可以使用欄位和屬性將資訊儲存於物件中。

雖然欄位和屬性從用戶端應用程式的觀點來看並無分別,但它們在類別中的宣告方式卻不一樣。

欄位只是由類別(Class)公開(Expose)的公用變數,而屬性則使用Property程序來控制值的設定或傳回方式。

在一開始的時候有說到物件導向的封裝,Field與Property都是屬於物件的資料成員,而Field,除非是定義為一個常數(const)或是固定的變數(readonly),我們才會將此Field修飾為Public(公開),否則一旦將Field的修飾設為Public而且不對其存取加以限制,那麼只要使用此物件時都可以任意的修改這個Field,這就失去了物件封裝的意義,也危及資料的安全。

所以在物件導向裡,Field通常的修飾都是為private(私有),只有開放給物件內部使用,對外則不開放的,而物件資料的存取則是使用Property,Property可以使用get, set這兩種存取子去對資料的存取再做處理,在.NETFramework3.0之後有多增加一個「自動屬性實作」,讓屬性的get,set不必對存取子的內部再做邏輯處理,1:publicstringFullDescription2:{3:get;4:set;5:}但是如果有需要去做邏輯處理時,就不能使用自動實作屬性,自動實作屬性是在對資料只有單純存取時才適用。

而通常資料成員的封裝是要Field與Property一起搭配的, 1:privatestring_FullDescription;2:publicstringFullDescription3:{4:get5:{6:if(string.IsNullOrWhiteSpace(this._FullDescription))7:{8:this._FullDescription=string.Format("{0}-{1}",9:this.CategoryName,10:this.Description);11:}12:returnthis._FullDescription;13:}14:} Property:FullDescription為主要資料取得的地方,對外公開; Field:_FullDescription為物件私有成員,是用來存放屬性的資料。

MSDN-使用屬性(C#程式設計手冊) http://msdn.microsoft.com/zh-tw/library/w86s7x04.aspx 節錄整理: 屬性(Property)是欄位和方法的綜合體; 如果是物件的使用者,屬性會以欄位出現,存取屬性需要完全相同的語法。

而對於類別的實作者,屬性則是一或兩個程式碼區塊,代表get存取子(Accessor)和(或)set存取子。

get存取子的程式碼區塊會於讀取屬性時執行,而且set存取子的程式碼區塊會在指派新值給該屬性時執行。

不含set存取子的屬性會被視為唯讀,而不含get存取子的屬性會被視為唯寫;同時具有這兩種存取子的屬性則為可讀寫。

屬性並不會歸類為變數,這點與欄位不同。

因此,不可能將屬性當做ref(C#參考)或out(C#參考)參數來傳遞。

屬性能有許多用途: 可以在允許變更之前驗證資料; 可以在實際從其他某些來源(例如資料庫)擷取資料時,透明地在某一類別上公開資料; 也可以在資料變更(例如引發事件,或是變更其他欄位的值)時採取動作。

屬性在類別區塊內被宣告的方式是指定欄位存取層級、接著指定屬性的型別、再指定屬性的名稱,然後是宣告get存取子和(或)set存取子的程式碼區塊。

屬性可以標記為public、private、protected、internal或protectedinternal,這些存取修飾詞(Modifier)將定義類別使用者如何存取屬性。

相同屬性的get和set存取子可能具有不同的存取修飾詞。

例如,get可能具有public,以允許來自型別外部的唯讀存取,而set則可能具有private或protected。

如需詳細資訊,請參閱存取修飾詞(C#程式設計手冊)。

您可以使用static關鍵字,將屬性宣告為靜態屬性。

這讓呼叫端即使沒有類別的執行個體,也可以隨時使用屬性。

如需詳細資訊,請參閱靜態類別和靜態類別成員(C#程式設計手冊)。

屬性可以使用virtual關鍵字標記為虛擬屬性。

如此一來,衍生類別就可以使用override關鍵字覆寫屬性行為。

如需這些選項的詳細資訊,請參閱繼承(C#程式設計手冊)。

用來覆寫虛擬屬性的屬性也可以是sealed,對於衍生類別來說,該屬性即不再為虛擬的。

最後,您可以將屬性宣告為absrtact,表示類別中不會有實作,衍生類別必須撰寫本身的實作。

如需這些選項的詳細資訊,請參閱抽象和密封類別以及類別成員(C#程式設計手冊)。

MSDN-欄位 http://msdn.microsoft.com/zh-tw/library/ms173118.aspx 節錄整理如下: 「欄位」(Field)是一個任意型別的變數,直接在類別或建構中宣告。

欄位是其包含型別(ContainingType)的「成員」(Member)。

類別(Class)或結構(Struct)可能會有執行個體(Instance)欄位或靜態(Static)欄位,或者兩個都有。

執行個體欄位專屬於某個型別的執行個體。

如果您有類別T搭配執行個體欄位F,則您可以建立兩個型別T的物件,然後修改每個物件中F的值,而不會影響到另一個物件中的值。

相較之下,靜態欄位屬於類別本身所有,在該類別的所有執行個體之間共用。

對執行個體A所做的變更,執行個體B和C只要存取該欄位就會馬上看到。

一般來說,欄位只應用在具有private或protected存取範圍的變數上。

類別公開(Expose)給用戶端程式碼的資料應透過方法、屬性和索引子來提供。

透過以這些建構來間接存取內部欄位,您可以防範無效的輸入值。

儲存由公用屬性公開之資料的私用欄位稱為「支援存放區」(BackingStore)或「支援欄位」(BackingField)。

欄位通常用來儲存必須由一個以上類別方法存取的資料,以及其儲存時間比任何單一方法的存留期(Lifetime)都還要長的資料。

例如,表示行事曆日期的類別有三個整數欄位,分別為月、日和年。

不會在單一方法以外範圍使用的變數,應在方法主體當中宣告為「區域變數」(LocalVariable)。

您必須依序指定欄位的存取層級、欄位型別和欄位名稱,以在類別區塊中宣告欄位。

欄位可以標記為public、private、protected、internal或protectedinternal。

這些存取修飾詞將定義類別使用者如何存取欄位。

如需詳細資訊,請參閱存取修飾詞(C#程式設計手冊)。

欄位也可以選擇性地宣告為static。

這讓呼叫端即使沒有類別的執行個體,也可以隨時使用該欄位。

如需詳細資訊,請參閱靜態類別和靜態類別成員(C#程式設計手冊)。

欄位可以宣告為readonly。

若為唯讀欄位,就只能在初始化期間或在建構函式中指派值給該欄位。

staticreadonly欄位非常類似於常數,唯一不同的是,C#編譯器無法在編譯時期存取靜態唯讀欄位的值,只有在執行階段才能這麼做。

如需詳細資訊,請參閱常數(C#程式設計手冊)。

dustin-[大話設計模式]物件導向筆記1 http://www.dotblogs.com.tw/dustin/archive/2011/01/17/20848.aspx 屬性:是一個方法或一對方法,但在調用它的程式碼看來,它是一個欄位,即屬性適合以欄位的方式使用方法調用的場合。

欄位:儲存類別要滿足其設計所需要的資料,欄位是與類別相關的變數。

另外在「EffectiveC#:50SpecificWaystoImproveYourC#(EffectiveC#:改善C#程序的50種方法)」中也有提到, 「AlwaysUsePropertiesInsteadofAccessibleDataMembers.」使用属性,以避免將資料成員直接暴露外界。

詳細說明可參閱:LevelUp-[C#]EffectiveC#條款一:使用屬性代替公有欄位   因為在專案當中時常看到會有人用Reflection去取得Field的資料,但是正確的作法應該是要去取用Property的資料,尤其是ADO.NETEntityFramework去映射資料庫所產出的類別,例如: 1:[EdmEntityTypeAttribute(NamespaceName="NorthwindModel",Name="Category")]2:[Serializable()]3:[DataContractAttribute(IsReference=true)]4:publicpartialclassCategory:EntityObject5:{6:#regionFactory方法7: 8:///

9:///建立新Category物件。

10:///
11:///CategoryID屬性的初始值。

12:///CategoryName屬性的初始值。

13:publicstaticCategoryCreateCategory(global::System.Int32categoryID,global::System.StringcategoryName)14:{15:Categorycategory=newCategory();16:category.CategoryID=categoryID;17:category.CategoryName=categoryName;18:returncategory;19:}20: 21:#endregion22:#region基本屬性23: 24:///25:///沒有可用的中繼資料文件。

26:///
27:[EdmScalarPropertyAttribute(EntityKeyProperty=true,IsNullable=false)]28:[DataMemberAttribute()]29:publicglobal::System.Int32CategoryID30:{31:get32:{33:return_CategoryID;34:}35:set36:{37:if(_CategoryID!=value)38:{39:OnCategoryIDChanging(value);40:ReportPropertyChanging("CategoryID");41:_CategoryID=StructuralObject.SetValidValue(value);42:ReportPropertyChanged("CategoryID");43:OnCategoryIDChanged();44:}45:}46:}47:privateglobal::System.Int32_CategoryID;48:partialvoidOnCategoryIDChanging(global::System.Int32value);49:partialvoidOnCategoryIDChanged();50: 51:///52:///沒有可用的中繼資料文件。

53:///
54:[EdmScalarPropertyAttribute(EntityKeyProperty=false,IsNullable=false)]55:[DataMemberAttribute()]56:publicglobal::System.StringCategoryName57:{58:get59:{60:return_CategoryName;61:}62:set63:{64:OnCategoryNameChanging(value);65:ReportPropertyChanging("CategoryName");66:_CategoryName=StructuralObject.SetValidValue(value,false);67:ReportPropertyChanged("CategoryName");68:OnCategoryNameChanged();69:}70:}71:privateglobal::System.String_CategoryName;72:partialvoidOnCategoryNameChanging(global::System.Stringvalue);73:partialvoidOnCategoryNameChanged();74: 75:///76:///沒有可用的中繼資料文件。

77:///
78:[EdmScalarPropertyAttribute(EntityKeyProperty=false,IsNullable=true)]79:[DataMemberAttribute()]80:publicglobal::System.StringDescription81:{82:get83:{84:return_Description;85:}86:set87:{88:OnDescriptionChanging(value);89:ReportPropertyChanging("Description");90:_Description=StructuralObject.SetValidValue(value,true);91:ReportPropertyChanged("Description");92:OnDescriptionChanged();93:}94:}95:privateglobal::System.String_Description;96:partialvoidOnDescriptionChanging(global::System.Stringvalue);97:partialvoidOnDescriptionChanged();98: 99:///100:///沒有可用的中繼資料文件。

101:///
102:[EdmScalarPropertyAttribute(EntityKeyProperty=false,IsNullable=true)]103:[DataMemberAttribute()]104:publicglobal::System.Byte[]Picture105:{106:get107:{108:returnStructuralObject.GetValidValue(_Picture);109:}110:set111:{112:OnPictureChanging(value);113:ReportPropertyChanging("Picture");114:_Picture=StructuralObject.SetValidValue(value,true);115:ReportPropertyChanged("Picture");116:OnPictureChanged();117:}118:}119:privateglobal::System.Byte[]_Picture;120:partialvoidOnPictureChanging(global::System.Byte[]value);121:partialvoidOnPictureChanged();122: 123:#endregion124: 125:#region導覽屬性126: 127:///128:///沒有可用的中繼資料文件。

129:///
130:[XmlIgnoreAttribute()]131:[SoapIgnoreAttribute()]132:[DataMemberAttribute()]133:[EdmRelationshipNavigationPropertyAttribute("NorthwindModel","FK_Products_Categories","Products")]134:publicEntityCollectionProducts135:{136:get137:{138:return((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection("NorthwindModel.FK_Products_Categories","Products");139:}140:set141:{142:if((value!=null))143:{144:((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection("NorthwindModel.FK_Products_Categories","Products",value);145:}146:}147:}148: 149:#endregion150:} 在所有屬性的get,set都是去對私有的Field欄位做資料的存取。

  延伸閱讀:MSDN-封裝欄位重構(C#) http://msdn.microsoft.com/zh-tw/library/a5adyhe9(v=VS.100).aspx [封裝欄位](EncapsulateField)重構作業可讓您從現有欄位快速建立屬性,然後以新屬性的參考順利地更新程式碼。

當欄位為public(公用)時,可以直接存取該欄位的其他物件,都能在擁有該欄位的物件無法偵測到的情況下修改該欄位。

藉由使用屬性來封裝該欄位,您就可以禁止直接存取該欄位。

另外補充兩篇MSDN對於屬性設計與欄位設計的設計方針: 屬性設計 http://msdn.microsoft.com/zh-tw/library/ms229006.aspx 一般而言,方法表示動作,而屬性則表示資料。

屬性的使用與欄位一樣,這表示屬性在運算方面來說不應該是複雜的,或不應該產生副作用。

如需屬性設計的詳細資訊,請參閱索引屬性設計和屬性變更通知事件。

下列方針可協助您確保屬性的設計正確。

如果呼叫端不應該能夠變更屬性的值,一定要建立唯讀屬性。

請注意,屬性型別的可變動性會影響使用者可以變更的內容。

例如,如果您定義會傳回讀取/寫入集合的唯讀屬性,則使用者將無法為此屬性指派不同的集合,但是可以修該集合中的元素。

請勿提供僅set屬性。

如果無法提供屬性getter,請改用一個方法來實作此功能。

此方法名稱應該以Set做為開頭,後面接著原本的屬性名稱。

例如,AppDomain有一個稱為SetCachePath的方法,而沒有稱為CachePath的僅set屬性。

一定要為所有屬性提供合理的預設值,以確保預設值不會產生安全性漏洞或極無效率的設計。

一定要允許屬性依任何順序來設定,即使這樣會產生暫時無效的物件狀態時亦然。

如果屬性setter擲回例外狀況,一定要保留之前的值。

避免從屬性getter擲回例外狀況。

屬性getter應該是沒有任何先前條件的簡單作業;如果getter可能擲回例外狀況,請考慮將此屬性重新設計為方法;但是,這項建議不適用於索引子,索引子可能會因為無效的引數擲回例外狀況。

從屬性setter擲回例外狀況是有效且可接受的。

  欄位設計 http://msdn.microsoft.com/zh-tw/library/ms229057.aspx 欄位可保存與物件有關的資料。

在大多數的情況下,程式庫中的任何非靜態欄位應該不會讓開發人員看到。

下列方針可協助您在程式庫設計中正確使用欄位。

不要提供公用或受保護的執行個體欄位。

公用和受保護的欄位在版本控制上並不理想,因此不受程式碼存取安全性要求的保護。

請不要使用公開可見的欄位,而是要使用私用欄位,並透過屬性來進行公開。

要針對絕對不會變更的常數使用常數欄位。

例如,Math類別可將E和PI定義為靜態常數。

編譯器會將const欄位的值直接插入呼叫程式碼中,這表示在變更const值時,一定會遇到引入相容性問題所帶來的風險。

一定要針對預先定義的物件執行個體使用公用靜態唯讀欄位。

例如,DateTime類別會提供靜態唯讀欄位,您可使用此欄位來取得設定為最大或最小時間值的DateTime物件。

請參閱MaxValue和MinValue。

請不要將可變動型別的執行個體指派給唯讀欄位。

使用可變動型別建立的物件可以在建立之後修改。

例如,陣列和大多數集合都是可變動型別,而Int32,Uri和String則是不可變動型別。

對於保存可變動參考型別的欄位而言,唯讀修飾詞可避免欄位值被覆寫,但是並不會防止可變動型別被修改。

屬性與欄位要好好認識並區分,然後了解應該如何的使用,建立類別時,凡是要公開的資料成員應該使用Property而不是用Field,要把Field修飾為Public時,應該限定為const或是readonly。

使用Reflection對物件的資料成員進行存取,應該是對Property而不是Field。

  以上 張貼者: mrkt的程式學習筆記 於 9/22/201112:49:00下午 以電子郵件傳送這篇文章BlogThis!分享至Twitter分享至Facebook分享到Pinterest 標籤: C# 沒有留言: 張貼留言 較新的文章 較舊的文章 首頁 訂閱: 張貼留言(Atom) 提醒 千萬不要使用GoogleTalk(Hangouts)或Facebook及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。

最近七天熱門文章 ASP.NETMVC+jQueryEasyUITree無限階層的樹狀選單 ASP.NETMVC的ViewModel-基礎篇 換個好字型讓程式開發有效率 ASP.NETMVC專案分層架構Part.1初學者的起手式 ASP.NETMVC-檔案上傳的基本操作 屬性(Property)與欄位(Field) ASP.NETMVC3-DropDownList的基本設定方式 Dapper練習題-新增多筆或大量資料 LINQPad-好用到爆炸、.NET開發人員必備的好用工具 jQuery對下拉選單DropDownList的操作-1 載入中… tw.MVC 我的技能樹-提升自我等級 SkillTree.My課程 訂閱 發表文章 Atom 發表文章 留言 Atom 留言 關連網站 twMVC官方網站 twMVC臉書粉絲團 twMVC@GitHub KevinTseng@GitHub KevinTseng@點部落 線上學習資源 ASP.NETCoreDocumentation LearnAboutASP.NETMVC LearnAboutASP.NETWebAPI MVA-MicrosoftVirtualAcademy 常用連結 VisualStudio 網誌存檔 ►  2018 (9) ►  八月 (1) ►  七月 (3) ►  一月 (5) ►  2017 (5) ►  六月 (1) ►  四月 (2) ►  一月 (2) ►  2016 (26) ►  十一月 (4) ►  十月 (6) ►  九月 (1) ►  八月 (3) ►  六月 (4) ►  五月 (1) ►  四月 (3) ►  二月 (3) ►  一月 (1) ►  2015 (39) ►  十二月 (4) ►  十一月 (2) ►  十月 (1) ►  九月 (10) ►  七月 (3) ►  六月 (5) ►  五月 (1) ►  四月 (5) ►  三月 (3) ►  二月 (4) ►  一月 (1) ►  2014 (83) ►  十二月 (5) ►  十一月 (4) ►  十月 (9) ►  九月 (9) ►  八月 (12) ►  七月 (9) ►  六月 (16) ►  五月 (4) ►  四月 (4) ►  三月 (8) ►  二月 (1) ►  一月 (2) ►  2013 (118) ►  十二月 (12) ►  十一月 (11) ►  十月 (20) ►  九月 (12) ►  八月 (4) ►  七月 (11) ►  五月 (12) ►  四月 (10) ►  三月 (13) ►  二月 (6) ►  一月 (7) ►  2012 (103) ►  十二月 (8) ►  十一月 (5) ►  十月 (5) ►  九月 (9) ►  八月 (3) ►  七月 (10) ►  六月 (14) ►  五月 (8) ►  四月 (10) ►  三月 (11) ►  二月 (10) ►  一月 (10) ▼  2011 (72) ►  十二月 (10) ►  十一月 (7) ►  十月 (27) ▼  九月 (24) Firefox出現「發現容易停止回應的程式碼」警示訊息 JavaScript擴充String的屬性:startsWith,endsWith,contains 練習題:取得指定月份第幾週星期幾的日期(日期的操作) VisualStudio使用「附加至處理序」來進行偵錯 把正在開發的網站專案新增到IIS的站台 ASP.NETMVC2+MvcPaging+MiniProfiler連結出現錯誤? ASP.NETMVC3+MiniProfiler.MVC3偵測執行效能 ASP.NETMVC2+MiniProfiler偵測執行效能 屬性(Property)與欄位(Field) ASP.NETMVC-資料分頁(5)範例程式下載 ASP.NETMVC-資料分頁(4)MvcSimplePostPager+AJAX ASP.NETMVC-資料分頁(3)自訂分頁功能列MvcSimplePostPager ASP.NETMVC-資料分頁(2)自訂分頁功能列MvcSimplePager VisualStudio快速鍵整理-偵錯與建置 VisualStudio快速鍵整理-編輯 ASP.NETMVC-資料分頁(1)使用MvcPaging 練習題:於指定的日期區間中取出符合指定DayOfWeek的日期 練習題:取出兩個字串中有差異的字 .NET反組譯工具:ILSpy,TelerikJustDecompile LINQPad-好用到爆炸、.NET開發人員必備的好用工具 jQuery對下拉選單DropDownList的操作-2:連動下拉選單 jQuery對下拉選單DropDownList的操作-1 JavaScript-浮點數運算 JavaScript–String.format ►  七月 (4) ►  2010 (20) ►  九月 (12) ►  八月 (8) 標籤 分層架構 (9) 其他 (8) 測試 (19) 開發 (49) 資料分頁 (34) 監測記錄 (37) 練習題 (24) ASP.NET (28) ASP.NETCore (7) ASP.NETMVC (234) ASP.NETWebAPI (13) AttributeRouting (4) AutoMapper (9) Bootstrap (7) C# (81) CheckBoxList (7) Dapper (6) DI/IoC (9) Docker (5) DropDownList (24) Elasticsearch (3) ELMAH (14) EnterpriseLibrary (10) EntityFramework (43) GitHub (14) Glimpse (6) JavaScript (22) jQuery (49) jQueryEasyUI (16) JSON (13) LINQ (39) MicrosoftAzure (1) MiniProfiler (11) NanoPrifiler (5) NanoProfiler (5) NLog (12) NSubstitute (2) Oracle (15) Route (11) SkillTree.My (1) SQLServer (1) SublimeText2 (18) Telerik (1) TFService (3) Tools (42) twMVC (9) VisualStudio (67) 推薦部落格-中文 黑暗執行緒 Huan-Lin學習筆記 KingKongBruce記事 demo小鋪 點部落-In91 MSDN台灣部落格 SimpleThoughtsonEverything 點部落-愛流浪的小風 阿砮的學習手寫板-點部落 點部落-我的Coding之路 點部落-黃偉榮的學習筆記 天空的垃圾場 Dino'sSandbox 愛流浪的小風(Logdown) 分享好文章 總網頁瀏覽量 關於我自己 mrkt的程式學習筆記 檢視我的完整簡介



請為這篇文章評分?