標籤:
條款1 使用屬性代替可訪問的資料成員 屬性是個啥,誰在用?
1. C#的屬性在被訪問的時候看起來好像是資料成員,但其實是方法。
2. 在.NET架構中,一般使用屬性工作表達公有資料成員。
3. .NET架構中的資料繫結類支援屬性。
屬性比公有資料成員有啥好?
1. 隨著時間的推移,新的需求影響原來類型的實現。比如在員工管理系統中有如下代碼:
public class Person { private string name; public string Name { get{return name;} set{this.name = value;} } ....//其它屬性 } View Code
Person類聲明了一個Name的屬性,表示這個人的名字。程式運行了一段時間後,需求發生了變化,要求Name必須不為null或者empty。
我們一般的做法會是1)在介面輸入的地方增加驗證;2)寫一個單獨的程式或者sql修改資料庫的資料。但問題來了如果這個Person類有好幾個錄入的介面,比如員工的增加介面、員工修改介面,在修改的時候就要修改兩次。大家肯定發現了,如果有很多這樣介面,那麼就需要修改很多這樣的地方。再比如Person類被很多子類繼承了,比如Leader、BussinessMan等,那麼就需要在每個用到這些類地方進行修改。幸虧我們寫的是C#,幸虧你用的是屬性。只需要完成以下修改就可以到達我們的目的了。
public class Person { private string name; public string Name { get{return name;} set { if(string.IsNullOrEmpty(value)) { throw new ArgumentException("Name cannot be blank","Name"); } this.name = value; } } ....//其它屬性 } View Code
這樣是不是很方便?類似的,屬性添加多線程支援更方便、可以作為介面定義的一部分、可以聲明為虛屬性、存取權限控制等。這些都是平常大家都會用的,此處就不再細說。
2. 索引器
如果類型介面需要包含一些索引資料項目,那麼這個時候可以使用索引器。C#中索引器又叫含參屬性(parameterized property)。這個文法大家一般不會聲明,但卻都在使用。比如說
List<int> intList = new List<int>();
Console.Write(intList[0]);
大家可能經常寫這種代碼,但只是對這個文法的名字不太熟悉,或者經常寫但不知道如何聲明這種文法。其實這個就是索引器,聲明的文法也很簡單。比如一個人可能有多個地址(工作地址、家庭住址、籍貫地址等等),代碼如下:
public class Person { private Dictionary<string,Address> addrDic = new Dictionary<string,string>(); public Address this[string name] { get { return addrDic[name]; } set { this.addrDic[name] = value;//此處也可以改為先判斷有沒有key,沒有key就添加。 } } }
除此之外,C#還支援多維索引器,比如public object this[row,col],可以表示一個excel表格的某行某列的儲存格裡面的值,這樣封裝後的Excel協助類肯定比xx.GetExcelValue(row,col)這種方法更容易使用。
屬性有啥不好?
顯而易見,使用屬性的代碼沒有使用資料成員的代碼效率快(因為屬性本質上是方法)。但是,屬性也不見得比說那個資料成員的代碼慢。這是為什麼呢?JIT編譯器會對方法進行內聯處理(具體含義自行google),屬性作為方法的一種也是會進行內聯處理,那麼屬性和資料成員的效率就沒有區別。當然,即便沒有被內聯,屬性調用的效率相對於函數調用的成本也是可以忽略不計的,只有在一些極少數的情況下這種差別才值得我們注意。
可不可以先寫公有欄位,然後再改為屬性?
這個問題,大家只記住不可以就行了。具體原因如下:
1. 對於屬性和公有欄位使用的原始碼看起來一樣但IL代碼是不一樣的;
2. 如果一個類型的公有資料成員改為屬性,那麼會破壞二進位的相容性,在程式已經部署的情況下可能會帶來升級的麻煩。
總結
1. 對於暴漏在類型的公有介面或者受保護介面中的資料,我們應該使用屬性。
2. 對於具有序列或者字典特徵的類型,我們應該採用索引器。
3. 對於所有的資料成員,我們應該都應該聲明為私人。
Effective c#學習筆記(1)