C# 的唯讀自動屬性是怎樣煉成的 - Huan-Lin 學習筆記
文章推薦指數: 80 %
C# 1 public class Employee { private string _id; // 屬性背後的實際 ... 到了C# 2,getter 和setter 可以限定存取範圍,例如protected 和private。
首頁
關於我
首頁
Home
/
.NET
/
C#
/
C#的唯讀自動屬性是怎樣煉成的
C#的唯讀自動屬性是怎樣煉成的
MichaelTsai
2/12/2018
.NET,
C#
編輯
這兩天,我把《C#本事》第六章有關於C#6唯讀自動屬性的部分再細化、完善。
這個部分尚未發布至電子書平台,我先把它摘錄在這裡,稍加排版,供有需要的朋友參考。
C#1
在C#1,每⼀個屬性通常會有對應的私有欄位,以及⼀對⽤來讀寫屬性的⽅法,分別稱為getter和setter。
如以下範例所⽰:
//C#1
publicclassEmployee
{
privatestring_id;//屬性背後的實際欄位(backingfield)
publicstringID
{
get{return_id;}//屬性的讀取方法(getter)
set{_id=value;}//屬性的設定方法(setter)
}
}
註:屬性的「讀取方法」和「設定方法」有點拗口,不如用英文來得簡單而且不易混淆,所以接下來會直接寫getter和setter。
有了getter和setter,類別的私有欄位就等於是多了一層保護,不但可防止外界任意修改私有欄位(例如在setter裡面檢核外界傳入的value是否合法),還可以在getter裡面加入一些額外的運算邏輯來決定該回傳給外界什麼內容。
C#2
到了C#2,getter和setter可以限定存取範圍,例如protected和private。
其中一種很常見的用法,就是公開的getter搭配私有的setter,讓外界只能讀取屬性值,而不能修改它——也就是唯讀屬性的意思。
像這樣:
//C#2
publicclassEmployee
{
privatestring_id;
publicstringID
{
get{return_id;}//公開的getter不必、也不可加上`public`。
privateset{_id=value;}//只有類別自己才能修改屬性值。
}
}
值得一提的是,若getter或setter要讓外界存取,則不必、也不可以在前面加上public修飾詞。
這是因為屬性的getter和setter的存取範圍必須比屬性宣告時的存取範圍更「窄」。
以剛才的範例來說,屬性ID已經宣告為public,那麼如果要為它的getter或setter指定存取範圍,就只能用internal、protected、或private。
C#3
C#3增加了自動實作屬性(automaticallyimplementedproperties),或簡稱「自動屬性」。
這個新語法能夠讓我們在定義屬性時省去宣告私有欄位的麻煩,當類別裡面的屬性數量很多的時候,這個語法可以讓程式碼簡潔許多。
請看底下的範例:
//C#3:自動實作屬性(免寫私有欄位)。
publicclassEmployee
{
publicstringID{get;privateset;}
publicstringName{get;set;}
publicDateTimeBirthday{get;set;}
//想像底下還有一堆屬性,而我們能夠省下多少私有欄位的宣告。
publicEmployee(stringid)//建構子
{
ID=id;
}
}
請注意屬性ID可讓外界讀取,但是只有類別本身才能修改其值。
所謂的類別本身,當然包含類別的建構子和方法。
可是,如果我們希望這個唯讀屬性只允許在建構子中設定一次初始值,以後就再也不能修改了——即使在類別的其他方法中也不能修改,這種情況要怎麼寫呢?C#5沒辦法做到——除非使用唯讀的私有欄位,但程式碼寫起來比較囉嗦。
C#6
到了C#6,終於在「不可改變性」(immutability)這方面做了改進,提供更好的寫法,也就是「唯讀自動屬性」(read-onlyautomaticallyimplementedproperties)語法,像這樣:
//C#6:唯讀的自動屬性。
publicclassEmployee
{
publicstringID{get;}//沒有setter,這是個唯讀自動屬性。
publicEmployee(stringid)
{
ID=id;//設定唯讀自動屬性的初始值。
}
privatevoidChangeID(intid)
{
ID=id;//編譯失敗:ID是唯讀屬性。
}
}
如您所見,此處有兩個重點:
屬性ID只有getter,沒有setter了。
它是個唯讀自動屬性。
由於ID是唯讀屬性,因此即使是類別自己也無法修改ID的值——建構子除外。
除了建構子之外,C#6還提供了另一個地方可以讓我們設定自動屬性的初始值:在宣告屬性的時候就設定初始值。
請接著看下一節。
自動屬性的初始設定式
在C#6之前,自動屬性的初始值只能透過建構子來設定,而無法在宣告屬性的時候就設定初始值。
C#6對此做了改進,提供了「自動屬性初始設定式」(auto-propertyinitializers)語法,讓程式碼可以再簡潔一點。
如以下範例所示:
publicclassEmployee
{
publicstringID{get;privateset;}="A001";
publicstringName{get;set;}="Michael";
publicintAge{get;}=20;
}
此語法的主要特色,是在定義自動屬性的時候用=運算子來加上賦值敘述,以設定該屬性的初始值。
需注意的是,此賦值語法只能用於自動實作屬性;若用在一般的屬性,編譯時會報錯。
所以底下的程式碼無法通過編譯:
publicclassEmployee
{
privatestring_name;
publicstringName
{
get{return_name;}
set{_name=value;}
}="另壺沖"//編譯錯誤!只有自動屬性才允許初始設定式。
}
另外,自動屬性的初始設定式無法透過this來存取該類別的其他成員。
也就是說,如果想要在自動屬性的初始設定式中呼叫該類別的方法,則該方法必須是靜態方法。
請看以範例與註解中的說明:
publicclassEmployee
{
publicintAge{get;}=this.GetAge();//編譯失敗!不可呼叫instance方法。
publicintSalary{get;}=GetSalary();//可以呼叫靜態方法。
intGetAge(){return20;}
staticintGetSalary(){return20000;}//注意:這是個靜態方法。
}
關於不可變性
在結束之前,我想再提一下唯讀自動屬性所提供的「不可變性」(immutability)在寫程式的時候有什麼好處。
請看底下的範例:
publicclassEmployee
{
publicList
}
}
屬性Addresses是個唯讀自動屬性,一旦初始化完成,就不能在其他地方修改。
於是乎,外界可以取得Addresses串列,並且呼叫它的Add或Remove方法來增加或刪除元素,但是無法將這個Addresses屬性設定成null或指向其他串列。
參考以下範例:
publicstaticvoidMain()
{
varemp=newEmployee();
emp.Addresses.Add("嘉義市大馬路123號");//OK!
emp.Addresses=newList
}
此範例程式的.NETFiddle連結:https://dotnetfiddle.net/9TINL9
以上便是C#屬性語法的大致演進歷程。
若有遺漏或未盡詳細之處,歡迎補充、指正。
ShareThis:
Facebook
Twitter
相關文章:
C#
沒有留言:
訂閱:
張貼留言
(
Atom
)
臉書專頁
Huan-Lin學習筆記
近30天熱門文章
在Windows10環境上安裝WSL2
async與await
C#學習筆記:多執行緒(2)-分道揚鑣
C#學習筆記:多執行緒(1)-從零開始
文章分類
.NET
(245)
C#
(99)
ASP.NET
(82)
VisualStudio
(48)
閱讀筆記
(48)
寫作與出版
(44)
PatternsandPractices
(42)
譯言難盡
(37)
版本控制
(28)
軟體開發
(27)
IT雜記
(26)
TroubleShooting
(16)
DependencyInjection
(15)
網頁前端
(14)
ContinuousIntegration
(12)
EntityFramework
(10)
IIS
(9)
SQLServer
(9)
WPF
(8)
MyProjects
(7)
專案管理
(5)
WindowsForms
(4)
給這個部落格拍拍手
過往文章
►
2022
(18)
►
三月2022
(9)
►
二月2022
(8)
►
一月2022
(1)
►
2021
(1)
►
一月2021
(1)
►
2020
(20)
►
十二月2020
(1)
►
四月2020
(4)
►
三月2020
(6)
►
二月2020
(7)
►
一月2020
(2)
►
2019
(8)
►
十二月2019
(2)
►
十月2019
(1)
►
三月2019
(4)
►
二月2019
(1)
▼
2018
(41)
►
十二月2018
(2)
►
十一月2018
(1)
►
十月2018
(6)
►
九月2018
(4)
►
八月2018
(2)
►
七月2018
(4)
►
四月2018
(6)
►
三月2018
(2)
▼
二月2018
(9)
[小抄].NETStandard與.NETCore概念圖
使用VSTS來自動建置GitHubrepo
初探C#8的NullableReferenceTypes
明確實作介面的唯讀自動屬性
[小抄]選擇合適的.NET集合類型
C#的唯讀自動屬性是怎樣煉成的
比較幾個我知道的數位出版平台
《C#本事》更新通知(2018二月)
WindowsServer2003之P2V歷險記
►
一月2018
(5)
►
2017
(6)
►
八月2017
(1)
►
四月2017
(4)
►
二月2017
(1)
►
2016
(13)
►
九月2016
(2)
►
八月2016
(1)
►
七月2016
(4)
►
六月2016
(1)
►
四月2016
(2)
►
一月2016
(3)
►
2015
(20)
►
九月2015
(1)
►
八月2015
(3)
►
七月2015
(4)
►
六月2015
(1)
►
四月2015
(2)
►
三月2015
(1)
►
二月2015
(1)
►
一月2015
(7)
►
2014
(43)
►
十二月2014
(4)
►
十一月2014
(8)
►
十月2014
(1)
►
八月2014
(5)
►
七月2014
(1)
►
六月2014
(3)
►
五月2014
(3)
►
四月2014
(5)
►
三月2014
(6)
►
二月2014
(6)
►
一月2014
(1)
►
2013
(68)
►
十二月2013
(2)
►
十一月2013
(1)
►
十月2013
(12)
►
九月2013
(1)
►
八月2013
(5)
►
七月2013
(2)
►
六月2013
(8)
►
五月2013
(4)
►
四月2013
(4)
►
三月2013
(12)
►
二月2013
(6)
►
一月2013
(11)
►
2012
(89)
►
十二月2012
(16)
►
十一月2012
(11)
►
十月2012
(6)
►
九月2012
(8)
►
八月2012
(6)
►
七月2012
(11)
►
六月2012
(8)
►
五月2012
(6)
►
四月2012
(6)
►
二月2012
(7)
►
一月2012
(4)
►
2011
(54)
►
十二月2011
(6)
►
十一月2011
(3)
►
十月2011
(6)
►
九月2011
(6)
►
八月2011
(5)
►
七月2011
(3)
►
五月2011
(8)
►
四月2011
(5)
►
三月2011
(6)
►
二月2011
(5)
►
一月2011
(1)
►
2010
(55)
►
十二月2010
(8)
►
十一月2010
(11)
►
十月2010
(5)
►
九月2010
(8)
►
八月2010
(5)
►
七月2010
(1)
►
五月2010
(1)
►
四月2010
(9)
►
二月2010
(1)
►
一月2010
(6)
►
2009
(69)
►
十二月2009
(4)
►
十一月2009
(3)
►
十月2009
(3)
►
九月2009
(7)
►
八月2009
(3)
►
七月2009
(5)
►
六月2009
(3)
►
五月2009
(5)
►
四月2009
(8)
►
三月2009
(9)
►
二月2009
(8)
►
一月2009
(11)
►
2008
(47)
►
十二月2008
(7)
►
十一月2008
(7)
►
九月2008
(2)
►
八月2008
(1)
►
七月2008
(2)
►
六月2008
(6)
►
五月2008
(4)
►
四月2008
(11)
►
三月2008
(3)
►
二月2008
(4)
►
2007
(4)
►
十一月2007
(1)
►
九月2007
(1)
►
八月2007
(1)
►
七月2007
(1)
►
2006
(3)
►
十二月2006
(1)
►
六月2006
(1)
►
五月2006
(1)
追蹤者
總網頁瀏覽量
CreatedBySoraTemplates|DistributedByFreeBloggerTemplates
技術提供:Blogger.
回頂端⬆️
延伸文章資訊
- 1Learn C# Properties: Getters and Setters at ... - Codeasy
" Value is a placeholder for the value that is assigned to the property Age. Because we defined t...
- 2Getter and Setter In C# 簡短的要命 - 技術筆記- 痞客邦
因此才需要把過程用getter setter 封裝起來 !! (還有許多價值在此不論). 回到C# !! class Student{. public string name{get;set;}.
- 3使用屬性- C# 程式設計手冊 - Microsoft Docs
- 4C# Properties (GET, SET) - Tutlane
- 5c# getters and setters causing stack overflow - Unity Forum
i'm trying to make my code a bit more OO and so i added getter and setters on a few publics to li...