日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

1.1 - C#语言习惯 - 使用属性而不是可访问的数据成员

發布時間:2025/1/21 C# 84 豆豆
生活随笔 收集整理的這篇文章主要介紹了 1.1 - C#语言习惯 - 使用属性而不是可访问的数据成员 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

  屬性一直是C#語言中的一等公民。自1.0版本以來,C#對屬性進行了一系列的增強,讓其表達能力不管提高。你甚至可以為setter和getter指定不同的訪問權限。

  隱式屬性也極大降低了聲明屬性時的工作量,不會比聲明數據成員麻煩多少。

?

  若你仍然在類型中聲明公有成員,或是仍在手工編寫set或get之類的方法,那么快停下來吧。

  屬性允許將數據成員作為公共接口的一部分暴露出去,同時仍舊提供面向對象環境下所需要的封裝。

  屬性這個語言元素可以讓你像訪問數據成員一樣使用,但其底層依舊使用方法實現。

?

  類型的某些成員確實非常適合作為數據,例如某個客戶的名稱,某個站點的x、y坐標或上一年度的收入等。

  而屬性則讓你可以創建出類似于數據訪問,但實際上卻是方法調用的借口,自然也可以享受到方法調用的所有好處。

  客戶代碼訪問屬性時,就像是在訪問公有的字段,不過其底層使用方法實現,其中可以自由定義屬性訪問器的行為。

?

  .NET Framework假設你會對公有數據成員使用屬性。

  實際上,.NET Framework中的數據綁定類僅支持屬性,而不支持公有數據成員。

  對于類所有的數據綁定類庫均是如此,包括WPF、WinForms和Silverlight。數據綁定會將某個對象的一個屬性和某個用戶界面控件相互關聯起來。

  數據綁定機制將使用反射來找到類型中的特定屬性:

1 textBoxCity.DataBindings.Add("Text", address, "City");

  這段代碼將textBoxCity控件的Text屬性綁定到了address對象的City屬性上。

  公有的數據成員并不推薦使用,因此Framework Class Library設計其也不支持其實現綁定。這樣的設計也保證了你必須選擇合適的面向對象技術。

?

  確實,數據綁定只是用在用戶界面邏輯中會使用到的類中。但這并不意味著屬性僅應該用在UI邏輯中,其他類和結構中也應使用屬性。

  在日后產生新的需求或行為時,屬性更易于修改。

  例如,你會很快有這樣的想法,客戶對象不應該有空白的名稱。若你使用了公有屬性來封裝Name,那么只要修改一處即可:

1 public class Customer 2 { 3 private string name; 4 public string Name 5 { 6 get { return name; } 7 set 8 { 9 if (string.IsNullOrEmpty(value)) 10 { 11 throw new ArgumentException("Name cannot be blank!", "Name"); 12 } 13 name = value; 14 } 15 } 16 }

?

  若是使用了公有的數據成員,那么就需要查找每一處設置客戶名稱的代碼并逐一修復。這將花費大量的時間。

?

  因為屬性是使用方法來實現的,所以添加多線程支持也非常簡單。

  很容易即可在屬性的get和set訪問器中作如下的修改,從而支持對數據的同步訪問:

1 public class Customer 2 { 3 private object syncHandle = new object(); 4 5 private string name; 6 public string Name 7 { 8 get 9 { 10 lock (syncHandle) 11 { 12 return name; 13 } 14 } 15 set 16 { 17 if (string.IsNullOrEmpty(value)) 18 { 19 throw new ArgumentException("Name cannot be blank!", "Name"); 20 } 21 lock (syncHandle) 22 { 23 name = value; 24 } 25 } 26 } 27 }

?

  屬性可以擁有方法的所有語言特性。例如,屬性可以為虛的(virtual):

1 public class Customer 2 { 3 public virtual string Name 4 { 5 get; 6 set; 7 } 8 }

  注意,上述例子中使用了C# 3.0中的隱式屬性語法。使用屬性來封裝私有字段是一個常用的模式。

  通常而言,我們并不需要驗證屬性的getter或setter邏輯。

  因為語言本身提供了簡化的隱式屬性語法,力求盡量降低開發人員的輸入工作,即將一個簡單的字段暴露或屬性。

  編譯器將為你創建一個私有的成員字段,并自動生成最簡單的get和set訪問器的邏輯。

?

  你還可以將屬性聲明為抽象的(abstract),以類似隱式屬性語法的形式將其定義在接口中。

  下面的例子就將屬性定義在了一個泛型接口中。

  需要注意的是,雖然其語法和隱式屬性完全相同,但是編譯器卻不會自動生成任何實現。

  接口只是定義了一個契約,強制所有實現了該接口的類型都必須滿足。

1 public interface INameValuePair<T> 2 { 3 string Name 4 { 5 get; 6 } 7 8 T value 9 { 10 get; 11 set; 12 } 13 }

?

  屬性是一種全功能的、第一等的語言元素,能夠一方法調用的形式訪問或修改內部數據。成員函數中可以實現的功能均可在屬性中實現。

?

  屬性的訪問器將作為兩個獨立的方法變異到你的類型中。在C#中,你可以為get和set訪問器制定不同的訪問權限。

  這樣即可更精妙的控制作為屬性暴露出來的數據成員的可見性。

?

1 public class Customer { 2 public virtual string Name 3 { 4 get; 5 protected set; 6 } 7 }

  上述屬性語法的表達含義圓圓超出了簡單數據字段的范疇。

  若類型需要包含并暴露出可索引的項目,那么可以使用索引器(即支持參數的屬性);若想反悔序列中的項,創建一個屬性會是個不錯的做法。

1 public class User 2 { 3 private string name; 4 5 public string Name 6 { 7 get { return name; } 8 set { name = value; } 9 } 10 11 // 獲取Name中的指定字符 12 public char this[int index] 13 { 14 get 15 { 16 if (index < 0) 17 { 18 throw new ArgumentException("Index must be more than 0!", "index"); 19 } 20 return name[index]; 21 } 22 } 23 } 24 class Program 25 { 26 static void Main(string[] args) 27 { 28 User mrZhang = new User() { Name = "張董" }; 29 30 Console.WriteLine(mrZhang[0]); 31 } 32 } 索引器(支持參數的屬性)

  運行結果:

?

  索引器和單一條目屬性有著同樣的語言支持:他們都是作為方法實現的,因此可以在索引器內部實現任意的驗證或計算邏輯。

  索引器也可以為虛的或抽象的,可聲明在接口中,可以為只讀或讀寫。

?

  一維且使用數字作為參數的索引器也可以參與數據綁定。使用非整數的索引器可用來定義Map和Dictionary:

1 public Address this[string name]
2 {
3 get { return addressValues[name]; } 4 set { addressValues[name] = value; } 5 }

?

?

  C#中支持多維數組,類似的,我們也可以創建多維索引器,每一個維度上可以使用同樣或不同的類型:

1 public int this[int x, int y] 2 { 3 get { return ComputeValue(x, y); } 4 } 5 6 public int this[int x, string name] 7 { 8 get { return ComputeValue(x, name); } 9 }

?

  需要注意的是,所有的索引器都是用this關鍵字聲明,C#不支持為索引器命名。

  因此,類型中每個不同的索引器都必須有不同的參數列表,一面混淆。

  幾乎屬性上的所有特性都能應用到索引器上。索引器也可為虛的或抽象的,可以對setter和getter給出不同的訪問限制,不過卻不能像屬性那樣創建隱式索引器。

?

  屬性的功能很強大,是個不錯的改進。

  但你是不是還在想能不能先用數據成員來實現,而在稍后需要其他各種功能的時候再改成屬性呢?

  這看似是個不錯的策略,不過實際上卻行不通。

  考慮如下這個類的定義:

1 // using public data members, bad practice 2 public class Customer 3 { 4 public string Name; 5 // remaining implementation omitted 6 }

?

  這個類描述一個客戶(Customer),包含了一個名稱(Name)。你可以使用熟悉的成員表示方法獲取或設置該名稱:

1 Customer zhangDong = new Customer(); 2 zhangDong.Name = "張董"; 3 string name = zhangDong.Name;

?

  看似簡單直觀,你也會認為若是日后將Name改成屬性,那么代碼也可以無需修改保持正常。

  但這個答案并不是完全正確的。

  屬性僅僅是訪問時類似于數據成員,這是語法所實現的目的。

  不過屬性并不是數據,屬性的訪問和數據的訪問將會生成不同的MSIL(Microsoft Intermediate Language,微軟中間語言)指令。

?

  雖然屬性和數據成員在源代碼層次上是兼容的,不過在二進制層面上卻大相徑庭。

  這也就意味著,若將某個公有的數據成員改成了與之等同的共有屬性,那么久必須重新編譯所有用到該共有數據成員的代碼。

  C#把二進制程序及作為一等公民看待。該語言本身的一個目標就是支持發布某個單一程序集時,不需要更新整個的應用程序。

  而這個將數據成員改為屬性的簡單操作卻破壞掉了二進制兼容性,也就會讓更新單一程序集變得非常困難。

?

  若是查看屬性生成的IL,那么你或許會想比較一下屬性和數據成員的性能。

  屬性當然不會比數據成員訪問快,不過也不會比其慢多少。

  JIT編譯器將內聯一些方法調用,包括屬性訪問器。當JIT編譯器內聯了屬性訪問器時,數據成員和屬性的訪問效率即可持平。

  即使某個屬性訪問器沒有被內聯,其性能差距也實在是微乎其微,僅僅一次函數調用之別而已。只有在某些極端情況下,二者的差距才會有所影響。

  

  在調用方法看,屬性雖然是方法,但它和數據卻有著類似的概念。這會使你的調用者對屬性有著一些潛意識的認識。

  例如,調用者會把屬性訪問當成是數據的訪問。

  不管怎樣,二者看上去很像描述性訪問器應該滿足這些潛意識的預期。

  get訪問器不應該有可被觀察到的副作用。set訪問器會修改狀態,用戶應該可以看到調用后帶來的改變。

?

  調用者也會對屬性訪問器的性能有著一定的預期。

  屬性的訪問就像是訪問一個數據字段,因此不會與訪問數據由太過明顯的性能差別。

  屬性訪問器不應該執行長時間的計算,或進行跨應用的調用(例如執行數據庫查詢等),或是其他任何與調用者期待不符的耗時操作。

?

  無論何時需要在類型的共有或保護接口中暴露數據,都應該使用屬性。你也應該使用索引器來暴露序列或字典。

  所有的數據成員都應該是私有的,沒有任何例外。

  這樣你就立即得到了數據綁定的支持,也便于日后瑞方法實現的各種修改。

  對于將任何變量封裝到一個屬性所需的額外輸入工作其實不會占用太多時間,而日后若是需要使用屬性來更正設計,則會花去大量的時間。

  現在多投入一點點,換來的是今后維護時的更加游刃有余。

?

總結

以上是生活随笔為你收集整理的1.1 - C#语言习惯 - 使用属性而不是可访问的数据成员的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。