• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • C#銳利體驗之第八講 索引器與操作符重載

    發表于:2007-07-14來源:作者:點擊數: 標簽:
    C#銳利體驗之第八講 索引器與操作符重載: 索引器 索引器(Indexer)是C#引入的一個新型的類成員,它使得對象可以像數組那樣被方便,直觀的引用。索引器非常類似于我們前面講到的屬性,但索引器可以有參數列表,且只能作用在實例對象上,而不能在類上直接作用
    C#銳利體驗之第八講 索引器與操作符重載:

    索引器

    索引器(Indexer)是C#引入的一個新型的類成員,它使得對象可以像數組那樣被方便,直觀的引用。索引器非常類似于我們前面講到的屬性,但索引器可以有參數列表,且只能作用在實例對象上,而不能在類上直接作用。下面是典型的索引器的設計,我們在這里忽略了具體的實現。

    class MyClass{    public object this [int index]    {        get        {            // 取數據        }        set         {            // 存數據        }    }}

    索引器沒有像屬性和方法那樣的名字,關鍵字this清楚地表達了索引器引用對象的特征。和屬性一樣,value關鍵字在set后的語句塊里有參數傳遞意義。實際上從編譯后的IL中間語言代碼來看,上面這個索引器被實現為:

    class MyClass{    public object get_Item(int index)    {          // 取數據    }    public void set_Item(int index, object value)	 {			//存數據    }}

    由于我們的索引器在背后被編譯成get_Item(int index)和set_Item(int index, object value)兩個方法,我們甚至不能再在聲明實現索引器的類里面聲明實現這兩個方法,編譯器會對這樣的行為報錯。這樣隱含實現的方法同樣可以被我們進行調用,繼承等操作,和我們自己實現的方法別無二致。通曉C#語言底層的編譯實現為我們下面理解C#索引器的行為提供了一個很好的基礎。

    和方法一樣,索引器有5種存取保護級別,和4種繼承行為修飾,以及外部索引器。這些行為同方法沒有任何差別,這里不再贅述。唯一不同的是索引器不能為靜態(static),這在對象引用的語義下很容易理解。值得注意的是在覆蓋(override)實現索引器時,應該用base[E]來存取父類的索引器。

    和屬性的實現一樣,索引器的數據類型同時為get語句塊的返回類型和set語句塊中value關鍵字的類型。

    索引器的參數列表也是值得注意的地方?!八饕钡奶卣魇沟盟饕鞅仨毦邆渲辽僖粋€參數,該參數位于this關鍵字之后的中括號內。索引器的參數也只能是傳值類型,不可以有ref(引用)和out(輸出)修飾。參數的數據類型可以是C#中的任何數據類型。C#根據不同的參數簽名來進行索引器的多態辨析。中括號內的所有參數在get和set下都可以引用,而value關鍵字只能在set下作為傳遞參數。

    下面是一個索引器的具體的應用例子,它對我們理解索引器的設計和應用很有幫助。

    using System;class BitArray{	int[] bits;	int length;	public BitArray(int length) 	{		if (length < 0) 			throw new ArgumentException();		bits = new int[((length - 1) >> 5) + 1];			this.length = length;	}	public int Length 	{		get { return length; }	}	public bool this[int index] 	{		get 		{			if (index < 0 || index >= length) 				throw new IndexOutOfRangeException();			elsereturn (bits[index >> 5] & 1 << index) != 0;		}		set		{			if (index < 0 || index >= length)				throw new IndexOutOfRangeException();			else if(value) 				bits[index >> 5] |= 1 << index;			else				bits[index >> 5] &= ~(1 << index);		}	}}class Test{	static void Main() 	{		BitArray Bits=new BitArray(10);		for(int i=0;i<10;i++)			Bits[i]=(i%2)==0;                        			Console.Write(Bits[i]+"  ");}}

    編譯并運行程序可以得到下面的輸出:

      True False True False True False True False True False

    上面的程序通過索引器的使用為用戶提供了一個界面友好的bool數組,同時又大大降低了程序的存儲空間代價。索引器通常用于對象容器中為其內的對象提供友好的存取界面--這也是為什么C#將方法包裝成索引器的原因所在。實際上,我們可以看到索引器在.NET Framework類庫中有大量的應用。

    操作符重載

    操作符是C#中用于定義類的實例對象間表達式操作的一種成員。和索引器類似,操作符仍然是對方法實現的一種邏輯界面抽象,也就是說在編譯成的IL中間語言代碼中,操作符仍然是以方法的形式調用的。在類內定義操作符成員又叫操作符重載。C#中的重載操作符共有三種:一元操作符,二元操作符和轉換操作符。并不是所有的操作符都可以重載,三種操作符都有相應的可重載操作符集,列于下表:

      一元操作符 + - ! ~ ++ -- true false
      二元操作符 + - * / % & | ^ << >> == != > < >= <=
      轉換操作符 隱式轉換()和顯式轉換()

    重載操作符必須是public和static 修飾的,否則會引起編譯錯誤,這在操作符的邏輯語義下是不言而喻的。父類的重載操作符會被子類繼承,但這種繼承沒有覆蓋,隱藏,抽象等行為,不能對重載操作符進行virtual sealed override abstract修飾。操作符的參數必須為傳值參數。我們下面來看一個具體的例子:

    using System;class Complex{	double  r, v;  //r+ v i	public Complex(double r, double v)	{		this.r=r;		this.v=v;	}	public static Complex operator +(Complex a, Complex b) 	{		return new Complex(a.r+b.r, a.v+b.v);	}	public static Complex operator -(Complex a)	{		return new Complex(-a.r,-a.v);	}	public static Complex operator ++(Complex a) 	{  		double r=a.r+1;  		double v=a.v+1;		return new Complex(r, v);	}	public void Print()	{		Console.Write(r+" + "+v+"i");	}}class Test{	public static void Main()	{		Complex a=new Complex(3,4);		Complex b=new Complex(5,6);				Complex c=-a;		c.Print();		Complex d=a+b;		d.Print();				a.Print();		Complex e=a++;		a.Print();		e.Print();		Complex f=++a;		a.Print();		f.Print();			}}

    編譯程序并運行可得到下面的輸出:

      -3 + -4i 8 + 10i 3 + 4i 4 + 5i 3 + 4i 5 + 6i 5 + 6i

    我們這里實現了一個“+”號二元操作符,一個“-”號一元操作符(取負值),和一個“++”一元操作符。注意這里,我們都沒有對傳進來的參數作任何改變--這在參數是引用類型的變量是尤其重要,雖然重載操作符的參數只能是傳值方式。而我們在返回值時,往往需要“new”一個新的變量--除了true和false操作符。這在重載“++”和“--” 操作符時尤其顯得重要。也就是說我們做在a++時,我們將丟棄原來的a值,而取代的是新的new出來的值給a! 值得注意的是e=a++或f=++a中e的值或f的值根本與我們重載的操作符返回值沒有一點聯系!它們的值僅僅是在前置和后置的情況下獲得a的舊值或新值而已!前置和后置的行為不難理解。

    操作符重載對返回值和參數類型有著相當嚴格的要求。一元操作符中只有一個參數。操作符“++”和“--”返回值類型和參數類型必須和聲明該操作符的類型一樣。操作符“+ - ! ~”的參數類型必須和聲明該操作符的類型一樣,返回值類型可以任意。true和false操作符的參數類型必須和聲明該操作符的類型一樣,而返回值類型必須為bool,而且必須配對出現--也就是說只聲明其中一個是不對的,會引起編譯錯誤。參數類型的不同會導致同名的操作符的重載--實際上這是方法重載的表現。

    二元操作符參數必須為兩個,而且兩個必須至少有一個的參數類型為聲明該操作符的類型。返回值類型可以任意。有三對操作符也需要必須配對聲明出現,它們是“==”和“!=”,“>”和“<”,“>=”和“<=”。需要注意的是兩個參數的類型不同,雖然類型相同但順序不同都會導致同名的操作符的重載。

    轉換操作符為不同類型之間提供隱式轉換和顯式轉換,主要用于方法調用,轉型表達和賦值操作。轉換操作符對其參數類型(被轉換類型)和返回值類型(轉換類型)也有嚴格的要求。參數類型和返回值類型不能相同,且兩者之間必須至少有一個和定義操作符的類型相同。轉換操作符必須定義在被轉換類型或轉換類型任何其中一個里面。不能對系統定義過的轉換操作進行重新定義。兩個類型也都不能是object或接口類型,兩者之間不能有直接或間接的繼承關系--這三種情況系統已經默認轉換。我們來看一個例子:

    using System;public struct Digit{	byte value;	public Digit(byte value) 	{		if (value < 0 || value > 9) 			throw new ArgumentException();		this.value = value;	}	public static implicit operator byte(Digit d) 	{		return d.value;	}	public static explicit operator Digit(byte b) 	{		return new Digit(b);	}}

    上面的例子提供了Digit類型和byte類型之間的隱式轉換和顯式轉換。從Digit到byte的轉換為隱式轉換,轉換過程不會因為丟失任何信息而拋出異常。從byte到Digit的轉換為顯式轉換,轉換過程有可能因丟失信息而拋出異常。實際上這也為我們揭示了什么時候聲明隱式轉換,什么時候聲明顯示轉換的設計原則。不能對同一參數類型同時聲明隱式轉換和顯式轉換。隱式轉換和顯式轉換無需配對使用--雖然C#推薦這樣做。

    實際上可以看到,對于屬性,索引器和操作符這些C#提供給我們的界面操作,都是方法的某種形式的邏輯抽象包裝,它旨在為我們定義的類型的用戶提供一個友好易用的界面--我們完全可以通過方法來實現它們實現的功能。理解了這樣的設計初衷,我們才會恰當,正確地用好這些操作,而不致導致濫用和錯用。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>