国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

[CLR via C#]10. 屬性

2019-11-17 03:21:52
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

[CLR via C#]10. 屬性

一、無(wú)參屬性

  對(duì)于字段,強(qiáng)烈建議將所有的字段都設(shè)為PRivate。如果允許用戶(hù)或類(lèi)型獲取或設(shè)置狀態(tài)信息,就公開(kāi)一個(gè)針對(duì)該用途的方法。封裝了字段訪問(wèn)的方法通常稱(chēng)為訪問(wèn)器(accessor)方法。訪問(wèn)器方法可選擇對(duì)數(shù)據(jù)的合理性進(jìn)行檢查,確保對(duì)象的狀態(tài)永遠(yuǎn)不被破壞。如下代碼:

    private sealed class Employee    {        private String m_Name;        private Int32 m_Age;         public String GetName(){            return m_Name;        }         public void SetName(String value){            m_Name = value;        }         public Int32 GetAge(){            return m_Age;        }         public void SetAge(Int32 value){            if (value <= 0)                throw new ArgumentOutOfRangeException("value", "must be >0");            m_Age = value;        }    }

  想這樣的數(shù)據(jù)封裝有兩個(gè)缺點(diǎn)。第一:不得不實(shí)現(xiàn)額外的方法;第二、用戶(hù)必須調(diào)用方法。

  CLR提供了屬性(Property)的機(jī)制,它緩解了第一個(gè)缺點(diǎn)所造成的的影響,同事完全消除了第二個(gè)缺點(diǎn)。如下面代碼:
   private sealed class Employee {        private String m_Name;         private Int32 m_Age;           public String Name {            get { return (m_Name); }            set { m_Name = value; } // 關(guān)鍵字'value' 總是代表新值        }         public Int32 Age {            get { return (m_Age); }            set {                if (value <= 0)    // 關(guān)鍵字'value' 總是代表新值                    throw new ArgumentOutOfRangeException("value", "must be >0");                m_Age = value;            }        }    }

  于是就可以這樣調(diào)用:

  Employee emp = new Employee();  emp.Name = "Jeffrey Richter";  emp.Age = 45;   Console.WriteLine("Employee info: Name = {0}, Age = {1}", emp.Name, emp.Age);

  可將屬性想象成智能字段,即背后有額外邏輯的字段。CLR支持靜態(tài)、實(shí)例、抽象和虛屬性。屬性可以使用任意可訪問(wèn)性修飾符修飾。

  每個(gè)屬性都有一個(gè)名稱(chēng)和一個(gè)類(lèi)型(類(lèi)型不能為void).屬性不能重載。也就是說(shuō)不能定義名稱(chēng)相同,類(lèi)型不同的屬性。定義屬性時(shí),通常要同時(shí)指定get和set兩個(gè)方法。但是,可以省略set方法來(lái)定義一個(gè)只讀屬性,或者省略get方法定義一個(gè)只寫(xiě)屬性?! 《x屬性時(shí),取決屬性的定義,編譯器在最后的托管程序集中生成以下兩項(xiàng)或三項(xiàng):  *)代表屬性的get訪問(wèn)器方法的一個(gè)方法。僅在屬性定義了get訪問(wèn)器方法時(shí)生成。  *)代表屬性的set訪問(wèn)器方法的一個(gè)方法。僅在屬性定義了set訪問(wèn)器方法時(shí)生成。  *)托管程序集元數(shù)據(jù)中的一個(gè)屬性定義。這一項(xiàng)是肯定要生成的?! ∫郧懊娴腅mployee類(lèi)為例,編譯器將會(huì)生成4個(gè)方法定義。如圖:    編譯器在你指定的屬性名之前會(huì)附加get_或set_前綴,從而自動(dòng)生成這些方法的名稱(chēng)。C#內(nèi)建了對(duì)屬性的支持。當(dāng)編譯器發(fā)現(xiàn)代碼試圖獲取或設(shè)置一個(gè)屬性時(shí),它實(shí)際會(huì)生成對(duì)上述某個(gè)方法的一個(gè)調(diào)用。  1. 自動(dòng)實(shí)現(xiàn)屬性  如果只是為了封裝一個(gè)私有字段而創(chuàng)建一個(gè)屬性,C#還提供了一種更簡(jiǎn)單的語(yǔ)法,稱(chēng)為自動(dòng)實(shí)現(xiàn)的屬性(Automatically implemented Property,Aip)。下面是Name屬性的一個(gè)例子:
    private sealed class Employee {        //這是一個(gè)自動(dòng)實(shí)現(xiàn)屬性        public String Name {get;set;}    }

  2.合理定義屬性

  屬性和字段的比較:

  1)屬性可以是只讀或只寫(xiě)的,字段訪問(wèn)確總是可讀和可寫(xiě)。如果定義一個(gè)屬性,最好同時(shí)為它提供get和set訪問(wèn)器方法。  2)一個(gè)屬性方法可能拋出異常;字段訪問(wèn)永遠(yuǎn)不會(huì)拋出異常。  3)屬性不能作為out或ref參數(shù)傳給方法;字段卻可以?! ?)屬性方法可能花費(fèi)較長(zhǎng)時(shí)間執(zhí)行;字段的訪問(wèn)總是立即完成的?! ?)如果連續(xù)多次調(diào)用,屬性方法每次都可能返回一個(gè)不同的值;而字段每次調(diào)用都返回相同的值。  6)屬性方法可能造成明顯的side effect(指訪問(wèn)屬性時(shí),除了單純的設(shè)置或獲取屬性,還會(huì)造成對(duì)象狀態(tài)的改變);字段訪問(wèn)永遠(yuǎn)不會(huì)。  7)屬性方法可能需要額外的內(nèi)存,或者返回一個(gè)不正確的引用,指向不屬于對(duì)象狀態(tài)一部分的某個(gè)東西,這樣一來(lái),對(duì)返回對(duì)象的修改就作用不到原始對(duì)象身上了。相反,查詢(xún)字段返回的總是正確的引用,它指向的東西保證是原始對(duì)象狀態(tài)的一部分?! ‖F(xiàn)在的開(kāi)發(fā)人員對(duì)屬性的依賴(lài)有過(guò)之而無(wú)不及,經(jīng)常有沒(méi)有必要都使用屬性,仔細(xì)看下上面的比較,你會(huì)發(fā)現(xiàn)在極少數(shù)的情況下,才有必要定義屬性。屬性的唯一好處就是提供了簡(jiǎn)化的語(yǔ)法,和調(diào)用普通方法相比,屬性不僅不會(huì)提高代碼性能,還會(huì)妨礙對(duì)代碼的理解。建議就是讓開(kāi)發(fā)人員老老實(shí)實(shí)的寫(xiě)Getxxx和Setxxx方法,希望編譯器提供一種特殊的,簡(jiǎn)化的,有別于字段訪問(wèn)的語(yǔ)法,是開(kāi)發(fā)人員知道他們實(shí)際上是在調(diào)用一個(gè)方法。  3.對(duì)象和集合初始化器  我們經(jīng)常要構(gòu)造一個(gè)對(duì)象,然后設(shè)置對(duì)象的一些公共屬性(或字段)。為了簡(jiǎn)化這個(gè)常見(jiàn)的編程模式,C#語(yǔ)言支持一種特殊的對(duì)象初始化語(yǔ)法。比如:[()]代表"()"可要可不要。
Employee e = new Employee[()] { Name = "Jeff", Age = 45 }
  對(duì)象初始化器語(yǔ)法真正的好處在于,它允許在表達(dá)式的上下文(相對(duì)于語(yǔ)句的上下文)中編碼,允許組合多個(gè)函數(shù),進(jìn)而增強(qiáng)了代碼的可讀性。于是,就可以這么寫(xiě)了:
string s = new Employee() {Name = "Jeff", Age = 45}.ToString().ToUpper();
    4.匿名類(lèi)型  利用C#的匿名類(lèi)型,可以使用非常簡(jiǎn)潔的語(yǔ)法來(lái)聲明一個(gè)不可變的元組類(lèi)型。元組(Tuple)類(lèi)型是含有一組屬性的類(lèi)型,這些屬性通常以某種方式相互關(guān)聯(lián)。
//定義一個(gè)類(lèi)型,后再它的一個(gè)實(shí)例,并初始化它的屬性var o1 = new { Name = "Jeff", Year = 1964 };Console.WriteLine("Name={0}, Year={1}", o1.Name, o1.Year);

  第一行代碼創(chuàng)建了一個(gè)匿名類(lèi)型,沒(méi)有在new 關(guān)鍵字后制定類(lèi)型名稱(chēng),所以編譯器會(huì)為我自動(dòng)創(chuàng)建一個(gè)類(lèi)型名稱(chēng),而且不會(huì)告訴我這個(gè)名稱(chēng)是什么(這正是匿名類(lèi)型一詞的由來(lái)),但編譯器是知道的。雖然我不知道變量o1聲明的是什么類(lèi)型,但可以利用C#的"隱式推斷類(lèi)型局部變量"功能(var)。

  編譯器支持用另外兩種語(yǔ)法聲明匿名類(lèi)型中的屬性,它根據(jù)變量推斷出屬性名和類(lèi)型:

String Name = "Grant";DateTime dt = DateTime.Now;// 有兩個(gè)屬性的一個(gè)匿名類(lèi)型// 1. String Name 屬性設(shè)為"Grant"http:// 2. Int32 Year 屬性設(shè)為dt中的年份var o2 = new { Name, dt.Year };

  在這個(gè)例子中,編譯器判斷第一個(gè)屬性名為Name。由于Name是一個(gè)局部變量的名稱(chēng),所以編譯器將屬性類(lèi)型設(shè)為與局部變量相同的類(lèi)型:String。對(duì)于第二個(gè)屬性,編譯器使用字段/屬性的名稱(chēng):Year。Year是DateTime類(lèi)的一個(gè)Int32屬性,所以匿名類(lèi)型中的Year屬性也是一個(gè)Int32。

  如果編譯器看見(jiàn)你在源代碼中定義了多個(gè)匿名類(lèi)型,而且這些類(lèi)型具有相同的結(jié)構(gòu),那么它只會(huì)創(chuàng)建一個(gè)匿名類(lèi)型定義,但可以創(chuàng)建該類(lèi)型的多個(gè)實(shí)例。相同的結(jié)構(gòu),指在這些匿名類(lèi)型中,每個(gè)屬性都有相同的類(lèi)型和名稱(chēng),而且這些屬性的指定順序相同。  匿名類(lèi)型經(jīng)常和LINQ技術(shù)配合使用。可用LINQ進(jìn)行查詢(xún),從而生成由一組對(duì)象構(gòu)成的集合,這些對(duì)象都是相同的匿名類(lèi)型。然后,可以對(duì)結(jié)果集中的對(duì)象進(jìn)行處理。所有的這些都在一個(gè)方法中完成?! ?.System.Tuple類(lèi)型  在System命名空間,Microsoft定義了幾個(gè)泛型Tuple(元組)類(lèi)型。它們?nèi)繌腛bject派生,區(qū)別只在于元數(shù)(泛型參數(shù)的個(gè)數(shù))?! ≡谟?jì)算機(jī)編程中,一個(gè)函數(shù)或運(yùn)算的元數(shù)是指函數(shù)獲取的實(shí)參或操作數(shù)的個(gè)數(shù)。
//這是最簡(jiǎn)單的public class Tuple<T1> {    private T1 m_item1;    public Tuple(T1 item1) { m_Item1 = item1;}    public item1 { get { retuen m_Item1; } }}

  和匿名類(lèi)型相似,一旦創(chuàng)建好了一個(gè)Tuple,他就不可變了(所有屬性都只讀)。Tuple類(lèi)還提供了CompareTo,Equals,GetHashCode和ToString方法,另外還提供了一個(gè)Size屬性。除此之外,所有Tuple類(lèi)型都實(shí)現(xiàn)了IstruralEquatable,IstructuralComparable和IComparable接口,所以可以比較兩個(gè)Tuple對(duì)象。

二、有參屬性  編程語(yǔ)言還支持所謂的有參屬性,它的get訪問(wèn)器方法接收一個(gè)或多個(gè)屬性,set訪問(wèn)器方法接收兩個(gè)或多個(gè)參數(shù)。C#語(yǔ)言把它們稱(chēng)為索引器。VB稱(chēng)為默認(rèn)屬性?! #使用數(shù)組風(fēng)格的語(yǔ)法來(lái)公開(kāi)有參屬性(索引器)。換句話說(shuō),可將索引器看作C#開(kāi)發(fā)人員重載[]操作符的一種方式。下面是一個(gè)實(shí)例BitArray類(lèi),它允許用數(shù)組風(fēng)格的語(yǔ)法來(lái)索引由該類(lèi)的一個(gè)實(shí)例維護(hù)的一組二進(jìn)制位。
internal sealed class BitArray {    // 容納了二進(jìn)制位的私有字節(jié)數(shù)組    private Byte[] m_byteArray;    private Int32 m_numBits;     // 下面的構(gòu)造器用于分配字節(jié)數(shù)組,并將所有位設(shè)為 0    public BitArray(Int32 numBits) {        // 先驗(yàn)證實(shí)參        if (numBits <= 0)            throw new ArgumentOutOfRangeException("numBits must be > 0");         // 保留位的個(gè)數(shù)        m_numBits = numBits;         // 為位數(shù)組分配字節(jié)        m_byteArray = new Byte[(m_numBits + 7) / 8];    }      // 下面是索引器(有參屬性)    public Boolean this[Int32 bitPos] {         // 下面是索引器的get訪問(wèn)器方法        get {            // 先驗(yàn)證實(shí)參            if ((bitPos < 0) || (bitPos >= m_numBits))                throw new ArgumentOutOfRangeException("bitPos", "bitPos must be between 0 and " + m_numBits);             // 返回指定索引處的位的狀態(tài)            return ((m_byteArray[bitPos / 8] & (1 << (bitPos % 8))) != 0);        }         // 下面是索引器的set訪問(wèn)器方法        set {            if ((bitPos < 0) || (bitPos >= m_numBits))                throw new ArgumentOutOfRangeException("bitPos", "bitPos must be between 0 and " + m_numBits);             if (value) {                // 將指定索引處的位設(shè)為true                m_byteArray[bitPos / 8] = (Byte)                   (m_byteArray[bitPos / 8] | (1 << (bitPos % 8)));            } else {                // 將指定索引處的位設(shè)為false                m_byteArray[bitPos / 8] = (Byte)                   (m_byteArray[bitPos / 8] & ~(1 << (bitPos % 8)));            }        }    }}

  BitArray類(lèi)的調(diào)用也非常簡(jiǎn)單:

  
private static void BitArrayTest() {        // 分配含有14個(gè)位的bitArray數(shù)組        BitArray ba = new BitArray(14);         // 調(diào)用set訪問(wèn)器方法,將編號(hào)為偶數(shù)的所有為設(shè)為true        for (Int32 x = 0; x < 14; x++) {            ba[x] = (x % 2 == 0);        }         // 調(diào)用get訪問(wèn)器方法顯示所有為的狀態(tài)        for (Int32 x = 0; x < 14; x++) {            Console.WriteLine("Bit " + x + " is " + (ba[x] ? "On" : "Off"));        }    }

  CLR本身并不區(qū)分無(wú)參屬性和有參屬性。對(duì)CLR來(lái)說(shuō),每個(gè)屬性都只是類(lèi)型中定義的一對(duì)方法和一些元數(shù)據(jù)。將this[...]作為表達(dá)一個(gè)索引器的語(yǔ)法,這純粹是C#團(tuán)隊(duì)自己的選擇,正因如此,C#只允許在對(duì)象的實(shí)例上定義索引器,C#沒(méi)有提供定義靜態(tài)索引器屬性的語(yǔ)法,雖然CLR是支持靜態(tài)有參屬性的。

三、調(diào)用屬性訪問(wèn)器方法時(shí)的性能

  對(duì)于簡(jiǎn)單的get和set訪問(wèn)器方法,JIT編譯器會(huì)將代碼內(nèi)聯(lián)。這樣一來(lái),使用屬性(而不使用字段)就沒(méi)有性能上的損失?! ?nèi)聯(lián)是指將一個(gè)方法的代碼直接編譯到它的方法中。這樣能避免在運(yùn)行時(shí)發(fā)出調(diào)用所產(chǎn)生的開(kāi)銷(xiāo),代價(jià)是編譯好的方法的額代碼會(huì)變得更大?! ∮捎趯傩栽L問(wèn)器方法通常只包含及少量代碼,所以對(duì)它們進(jìn)行內(nèi)聯(lián),反而會(huì)使最終生成的本地代碼更小,執(zhí)行更快。  JIT編譯器在調(diào)試代碼時(shí)不會(huì)內(nèi)聯(lián)屬性,因?yàn)檫@會(huì)變得難以調(diào)試。

四、屬性訪問(wèn)器的可訪問(wèn)性

  我們有時(shí)希望為get訪問(wèn)器方法指定一種可訪問(wèn)性,為set訪問(wèn)器方法指定另一種可訪問(wèn)性。如下:

public class SomeType {       private String m_name;       public String Name {             get { return m_name;}             protected set { m_name = value;}   }}

  定義一個(gè)屬性時(shí),如果兩個(gè)訪問(wèn)器方法需要具有不同的可訪問(wèn)性,C#語(yǔ)法要求必須為屬性本身指定限制最不大的那一種可訪問(wèn)性。然后,在兩個(gè)訪問(wèn)器中,只能選擇一個(gè)來(lái)應(yīng)用限制較大的那一種可訪問(wèn)性。如前面例子中,屬性本身聲明為public,set訪問(wèn)器方法聲明為protected(限制比public大)。

五、泛型屬性訪問(wèn)器方法

既然屬性本質(zhì)是方法,而且C#和CLR允許方法是泛型的,但是C#不允許定義泛型屬性。這從概念上講不通。屬性本用來(lái)表示一項(xiàng)可供查詢(xún)的或設(shè)置的對(duì)象特征。從概念上講,屬性是不具有行為的。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 华坪县| 巴中市| 金川县| 苍溪县| 麻阳| 平度市| 许昌县| 南皮县| 宁强县| 万安县| 渭源县| 杨浦区| 巫溪县| 卓资县| 香港| 宣汉县| 应用必备| 清流县| 宿松县| 岳阳市| 通许县| 太康县| 建瓯市| 新巴尔虎右旗| 会理县| 汽车| 高陵县| 珠海市| 伊金霍洛旗| 泸定县| 永宁县| 大余县| 榕江县| 福鼎市| 榕江县| 濮阳县| 乌拉特中旗| 定安县| 治县。| 静安区| 余庆县|