索引器 (indexer)
C#語言一個最令人感興趣的地方就是類的索引器(indexer)。簡單說來,所謂索引器就是一類特殊的屬性,通過它們你就可以像引用數組一樣引用自己的類。這就說明這一功能在創建集合類的場合特別有用,而在其他某些情況下,比如處理大型文件或者抽象某些有限資源等,能讓類具有類似數組的行爲當然也是非常有用的。
索引器允許類或結構的實例按照與數組相同的方式進行索引。索引器類似於屬性,不同之處在於它們的訪問器採用參數。它可以使得像數組那樣對對象使用下標。它提供了通過索引方式方便地訪問類的數據信息的方法,那麼首先讓我們概述下屬性這個概念以便了解些必要的背景知識。
屬性 (property):
所謂屬性方法其實就是特殊的類成員,它實現了對私有類域的受控訪問。在C#語言中有兩種屬性方法,其一是get,通過它可以返回私有域的值,其二是set,通過它就可以設置私有域的值。比如說,以下面的代碼爲例,其間創建了一個FirstName屬性,由它控制對私有類成員firstname的訪問:
所謂屬性方法其實就是特殊的類成員,它實現了對私有類域的受控訪問。在C#語言中有兩種屬性方法,其一是get,通過它可以返回私有域的值,其二是set,通過它就可以設置私有域的值。比如說,以下面的代碼爲例,其間創建了一個FirstName屬性,由它控制對私有類成員firstname的訪問:
class Person
{
private string firstname;
public string FirstName
{
get { return firstname; }
set { firstname = value; }
}
}
屬性聲明可以如下編碼:
Person p = new Person();
p.FirstName = "Lamont";
Console.WriteLine(p.FirstName);
這樣看來屬性聲明倒更像是域聲明,只不過它還聲明瞭兩個特殊的成員,MSDN說法就是所謂的訪問函數(accessor)。當某一表達式的右邊調用屬性或者屬性用作其他子程序(或者函數)的參數時即會調用get訪問函數。反之,當表達式左邊調用屬性並且通過隱式傳遞value參數設置私有域值的情況下就會調用set訪問函數。你可以創建只讀屬性,方法是省略set訪問函數,這樣任何設置屬性的嘗試都會產生編譯錯誤。
要聲明類或結構上的索引器,要使用this關鍵字,例如:
要聲明類或結構上的索引器,要使用this關鍵字,例如:
public int this[int index] //聲明索引器
{
// get and set 訪問
}
索引器的修飾符有:new、public、protected、internal、private、virtual、sealed、override、abstract和extern。當索引器聲明包含extern修飾符時,稱該索引器爲外部索引器。因爲外部索引器聲明不提供任何實際的實現,所以它的每個訪問器聲明都由一個分號組成。
索引器的簽名由其形參的數量和類型組成。它不包括索引器類型或形參名。如果在同一類中聲明一個以上的索引器,則它們必須具有不同的簽名。
索引器值不歸類爲變量;因此,不能將索引器值作爲ref或out參數來傳遞。
下面用一個例子來說明如何聲明和使用索引器。
class SampleCollection<T>
{
private T[] arr = new T[100];
public T this[int i]
{
get { return arr[i]; }
set { arr[i] = value; }
}
}
下面是如何使用上述代碼實現的索引器,具體代碼示例如下:
class Program
{
static void Main (string[] args)
{
SampleCollection<string> s = new SampleCollection<string>();
s[0] = "索引器的使用";
System.Console.WriteLine(s[0]);
}
}
C#並不將索引類型限制爲整數。例如,對索引器使用字符串可能是有用的。通過搜索集合內的字符串並返回相應的值,可以實現此類的索引器。如下所示:
using System;
using System.Collections;;
class IndexClass
{
private Hashtable ht = new Hashtable();
public object this[object key]
{
get { return ht[key]; }
set { ht[key] = value; }
}
}
下面再談談屬性與索引器的差別:
類的每一個屬性都必須擁有唯一的名稱,而類裏定義的每一個索引器都必須擁有唯一的簽名(signature)或者參數列表(這樣就可以實現索引器重載)。屬性可以是static(靜態的)而索引器則必須是實例成員。爲索引器定義的訪問函數可以訪問傳遞給索引器的參數,而屬性訪問函數則沒有參數。
類的每一個屬性都必須擁有唯一的名稱,而類裏定義的每一個索引器都必須擁有唯一的簽名(signature)或者參數列表(這樣就可以實現索引器重載)。屬性可以是static(靜態的)而索引器則必須是實例成員。爲索引器定義的訪問函數可以訪問傳遞給索引器的參數,而屬性訪問函數則沒有參數。
擴展:接口
類似數組的行爲常受到程序實現者的喜愛,所以你還可以爲接口定義索引器,IList和 IDictionary集合接口都聲明瞭索引器以便訪問其存儲的項目。
在爲接口聲明索引器的時候,記住聲明只是表示索引器的存在。你只需要提供恰當的訪問函數即可,不必包括範圍修飾符。以下代碼把索引器聲明爲接口IImplementMe的一部分:
在爲接口聲明索引器的時候,記住聲明只是表示索引器的存在。你只需要提供恰當的訪問函數即可,不必包括範圍修飾符。以下代碼把索引器聲明爲接口IImplementMe的一部分:
interface IImplementMe {
string this[int index]
{
get;
set;
}
}
相應實現的類則必須爲IimplementMe的索引器具體定義get和set訪問函數。
先寫到這裏,也只能理解到這一步了,有不足的地方希望能夠得到大家的批評指正。