ايندكسرها (Indexers)
با استفاده از ايندكسرها مي توان با يك كلاس همانند آرايه ها رفتار كرد. به مثال زير توجه كنيد :
using System;
///
/// A simple indexer example.
///
class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = new string[size];
for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}
public string this[int pos]
{
get
{
return myData[pos];
}
set
{
myData[pos] = value;
}
}
static void Main(string[] args)
{
int size = 10;
IntIndexer myInd = new IntIndexer(size);
myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";
Console.WriteLine("\nIndexer Output\n");
for (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}
}
}
در مثال فوق نحوه ي تعريف و استفاده از ايندكسرها را مي توان مشاهده كرد. كلاس IntIndexer حاوي آرايه اي به نام myData مي باشد. بدليل private بودن آن در خارج از كلاس قابل دسترسي نيست. اين آرايه در سازنده ي كلاس (متد IntIndexer) با كلمه ي empty مقدار دهي اوليه شده است.
عضو بعدي كلاس Indexer مي باشد و با كلمه ي كليدي this و براكتها مشخص شده ست (this[int pos]). همانطور كه ملاحظه مي فرماييد نحوه ي تعريف ايندكسرها شبيه به تعريف خواص مي باشد.
this [argument list]
{
get
{
// Get codes goes here
}
set
{
// Set codes goes here
}
}
خروجي مثال فوق به صورت زير است :
myInd[0]: empty
myInd[1]: empty
myInd[2]: empty
myInd[3]: Another Value
myInd[4]: empty
myInd[5]: Any Value
myInd[6]: empty
myInd[7]: empty
myInd[8]: empty
myInd[9]: Some Value
استفاده از اعداد صحيح روشي است متداول براي دسترسي به اعضاي آرايه ها در بسياري از زبانها اما ايندكسرها در سي شارپ فراتر از اين مي رود. ايندكسرها را مي توان با پارامترهاي متعددي تعريف كرد و هر پارامتر با نوعي مختلف (دقيقا همانند پارامترهاي ورودي متدها). البته محدوديتي كه اينجا وجود دارد در مورد نوع پارامتر ها است كه تنها مي تواند integers, enums, and strings باشد . بعلاوه قابليت Overloading ايندكسرها نيز وجود دارد. به همين جهت به آنها آرايه هاي هوشمند هم گفته مي شود (smart arrays) .مثال :
using System;
///
/// Implements overloaded indexers.
///
class OvrIndexer
{
private string[] myData;
private int arrSize;
public OvrIndexer(int size)
{
arrSize = size;
myData = new string[size];
for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}
public string this[int pos]
{
get
{
return myData[pos];
}
set
{
myData[pos] = value;
}
}
public string this[string data]
{
get
{
int count = 0;
for (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
count++;
}
}
return count.ToString();
}
set
{
for (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
myData[i] = value;
}
}
}
}
static void Main(string[] args)
{
int size = 10;
OvrIndexer myInd = new OvrIndexer(size);
myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";
myInd["empty"] = "no value";
Console.WriteLine("\nIndexer Output\n");
for (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}
Console.WriteLine("\nNumber of \"no value\" entries: {0}", myInd["no value"]);
}
}
در مثال فوق اولين ايندكسر با يك پارامتر از نوع اعداد صحيح تعريف شده است و در ايندكسر دوم از نوع رشته.
خروجي برنامه ي فوق به صورت زير است :
myInd[0]: no value
myInd[1]: no value
myInd[2]: no value
myInd[3]: Another Value
myInd[4]: no value
myInd[5]: Any Value
myInd[6]: no value
myInd[7]: no value
myInd[8]: no value
myInd[9]: Some Value
Number of "no value" entries: 7
نكته :
1- امضاي (ليست پارامترهاي) ايندكسر ها در يك كلاس بايد منحصر بفرد باشد .
2- تعريف يك ايندكسر به صورت استاتيك مجاز نيست.
در صورت نياز به ايندكسرهايي با پارمترهاي ورودي متعدد مي توان به صورت زير عمل كرد :
public object this[int param1, ..., int paramN]
{
get
{
// process and return some class data
}
set
{
// process and assign some class data
}
}
يك مثال ديگر :
using System;
class IndexExample
{
string Message;
public static void Main()
{
IndexExample obj=new IndexExample("Welcome");
/* This will access the String variable Message
using array like notation
*/
for(int i=0;i < obj.Length;i++)
{
Console.WriteLine(obj[i]);
}
obj[obj.Length-1]="e to C#";
Console.WriteLine(obj.Message);
}
public IndexExample(string s)
{
Message=s;
}
public string this[int i]
{
get
{
if(i >= 0 && i < Message.Length)
{
return Message.Substring(i,1);
}
else
{
return "";
}
}
set
{
if(i >= 0 && i < Message.Length)
{
Message=Message.Substring(0,i) + value + Message.Substring(i+1);
}
}
}
public int Length
{
get
{
if(Message!=null)
{
return Message.Length;
}
else
return 0;
}
}
}