CLR類型設計之屬性

          在以前的隨筆中,咱們探討了參數,字段,方法,咱們在開始屬性以前回顧一下,以前的探討實際上串聯起來就是OOP編程的思想,在接下來的文章中,咱們還會討論接口(就是行爲),舉個例子:咱們若是要作一個學生檔案,咱們須要先抽象出來有那些對象實體,好比有一個學生類,裏面有學生id,姓名,年齡,班級等字段。 可是這不能知足咱們的需求,咱們要作學生檔案管理,須要知道學生的每科成績,因此咱們還須要一個成績類,裏面定義了學生的學生Id,科目,科目分數,下面是兩個類的代碼示例算法

public sealed  class Student
    {
        //學員id
        public int StudentId;
        //姓名
        public string Name;
        //年齡
        public int Age;
        //班級名
        public string classname;
    }
    public sealed class Score {
        //學員id
        public int StudentId;
        //科目
        public string SubjectName;
        //成績
        public int Achievement;
    }
View Code

       有了這兩個類之後,咱們就能夠建立一個獲取學員成績的方法,方法的代碼示例就不寫了,OOP的思想最重要的在於儘量的模塊化可複用,固然爲了實現這些,還有繼承,多態等去實現目的,可是在繼續實現過程當中你可能會發現一些問題,當咱們須要使用上面類型的時候,能夠經過實例化直接使用,以下:編程

     Student stu = new Student();
            stu.Name = "蘇雲";
            stu.Age = 22;
            stu.classname = "fantasy";
View Code

      可是若是我輸入一個Age爲-15,程序也能夠經過,字段值就會被改變爲-15,年齡是不存在負數的,因此這個值是不該該經過的,這就是今天的主題,屬性設置,面向對象一條很重要的原則就是數據封裝,意味類型字段永遠不該該公開,不然很容易由於不恰當使用而破壞對象的狀態,如上文咱們輸入的負值,固然還有一些其餘緣由,好比線程安全,字段爲邏輯字段,其值存在於內存中的字節,經過某個算法獲取獲得。可是這樣作就會致使一個問題,外部方法想要訪問時,因爲內部不公開,因此外部沒法訪問c#

      CLR中提供了屬性機制,咱們徹底能夠不用擔憂上面的問題,咱們改寫一下例子一的代碼示例,在實例化學生的時候,若是Age<1,就會拋出異常,能夠看到是那個參數報出的異常,值是多少。數組

  public sealed  class Student
    {
        private int studentId;
        private string name;
        private int age;
        private string classname;
        //學員id
        public int StudentId { get { return (studentId); }set { studentId = value; } }
        //姓名
        public string Name{ get { return (name); }set { name = value; } }
        //年齡
        public int Age
        {
            get { return (age); }
            set
            {
                if (value<1)  throw new ArgumentOutOfRangeException("value", value.ToString(),"學生的年齡不能小於1歲");
                age = value;
                 }
        }
        //班級名
        public string Classname { get { return (classname); }set { classname = value; } }
    }
View Code

    屬性機制使用起來很簡單,每一個屬性都有名稱和類型(類型不能爲void),而且一個類中同一個字段名稱只能出現一次,只須要get,set兩個關鍵字,若是隻有get那就是隻讀字段,只有set是隻寫字段。也能夠在get上寫計算方法獲取到值,可是上述方法寫起來是否以爲很麻煩?C#還支持自動屬性實現,咱們改寫成績類,示例代碼以下,安全

  public sealed class Score {
        //學員id
        public int StudentId { get; set; }
        //科目
        public string SubjectName { get; set; }
        //成績
        public int Achievement { get; set; }
    }
View Code

   在C#中聲明get;set可是卻未提供對應方法,C#會自動聲明一個私有字段,這樣就能夠很快定義一個屬性,和寫字段是同樣的,但須要注意的是,屬性不能做爲out或ref參數傳給方法,而字段能夠ide

     對象和初始化器模塊化

      在以前的代碼中,咱們初始化學生類須要分兩步,第一實例化,第二賦值,但實際上咱們可使用更簡單的語法,對象初始化器初始化一個對象,只須要像下面這樣一句話就能夠初始化一個對象而且賦值,他作的事情和例子2是相同的。在集合中也可使用初始化器初始化集合。函數

 

重點: 若是類沒有無參的構造函數就會出現編譯時錯誤

 

Student stu1 = new Student() {
                Name="admain",Age=15,Classname="fantasy"
            };
View Code

    咱們提到集合也能夠用初始化器的方法初始化,可是集合的初始化和對象並不同,首先要求對象或字段繼承了IEnummerable<T>接口,咱們示例常見的Dictionary集合如何初始化this

1 Dictionary<int, string> dic = new Dictionary<int, string> {
2                 { 1,"張三"}, { 2,"李四"}
3             };
4             //等價於
5             dic.Add(1, "張三");
6             dic.Add(1, "李四");
View Code

     有參屬性:索引器spa

     一個屬性的get訪問器方法不接收參數,則稱爲無參屬性,用起來就和訪問字段同樣,除了這些與字段類似的屬性,還有一種有參屬性,C#裏稱其爲索引器,下文中全部有參屬性都用索引器替代,C#使用數組風格的語法來公開索引器,看下面的示例:

 1 class MyListBox
 2 {
 3     public ArrayList data = new ArrayList();
 4     public object this[int idx]  //this做索引器名稱,idx是索引參數
 5     {
 6         get
 7         {
 8             if (idx > -1 && idx < data.Count)
 9             {
10                 return data[idx];
11             }
12             else
13             {
14                 return null;
15             }
16         }
17         set
18         {
19             if (idx > -1 && idx < data.Count)
20             {
21                 data[idx] = value;
22             }
23             else if (idx <= data.Count)
24             {
25                 data.Add(value);
26             }
27             else
28             {
29                 throw new ArgumentOutOfRangeException("idx", idx, "超出數組索引範圍");
30             }
31         }
32     }
33 }
View Code

      咱們定義了一個類MyListBox,其中有一個ArrayList字段,在構造器中爲其默認初始化了,在下面的代碼中咱們看到了如何聲明一個索引器,咱們返回的類型是object,索引器的返回類型同樣不能夠void,c#使用this[...]表達索引器,而且C#不支持靜態索引器,儘管CLR支持靜態有參屬性,C#容許一個類型定義多個索引器,可是索引器參數集不能相同,其餘一些語言中支持定義多個相同簽名的索引器,由於其餘一些語言中索引器能夠自定命名,可是C#不容許這樣作,由於C#中不容許開發人員指定索引器名稱,C#爲一個類型中的全部索引器都默認提供了一個叫作Item的名稱,因此在C#中使用索引器只能經過不一樣簽名來區分選擇的索引器。

       CLR並不區分有參屬性和無參屬性,對CLR來講,每一個屬性都只是類型中定義的一對方法,和一些元數據。下面的示例是如何調用索引器。使用起來也很簡單吧

 1      //初始化MyListBox
 2             MyListBox ba = new MyListBox {
 3                 //集合初始化器初始化值
 4                 data = { "張三",20,30,40},
 5             };
 6             //調用添加方法爲其添加值
 7             ba.data.Add("5");
 8             ba.data.Add(6);
 9             for (int i = 0; i < ba.data.Count; i++)
10             {
11                 //使用索引器打印出指定值,具體實現請查看類中get方法
12                 Console.WriteLine(ba.data[i]);
13             }
View Code

      無參屬性,初始化器,有參屬性,有了這些你能夠在你的方法中更好的使用字段,而且讓你的數據封裝更加安全,可是CLR做者本人卻持有另一種觀點,做者以爲屬性不如封裝的方法。有興趣的朋友能夠本身翻閱CLR看看做者的觀點。

相關文章
相關標籤/搜索