آموزش سی شارپ – index گذاری اپراتورها
در این جلسه از سری آموزشی برنامه نویسی سی شارپ قصد بررسی index گذاری اپراتورها را داریم.
حتما قبل از بررسی index گذاری اپراتورها نوشتهی مطالب قبلی این دورهی آموزشی را با هشتگ #دوره آموزشی_سی_شارپ در سایت ما را مطالعه کنید.
آموزش سی شارپ index گذاری اپراتورها
معرفی Conversion Operators
Conversion operator یک شیء از کلاس شما را به نوع دیگری که مد نظرتان است تبدیل میکند. دو حالت از conversion operator موجود است.
implicit و explicit که فرم کلی آنها به شکل زیر است:
public static operator implicit target-type(source-type v)
{
return value;
}
public static operator explicit target-type(source-type v)
{
return value;
}
target-type مشخص کنندهی نوعی است که قصد دارید source-type را به آن تبدیل کنید و value مقدار کلاس، بعد از تبدیل است. Conversion operator اطلاعات را مطابق با target-type باز میگرداند. اگر conversion operator بهطور implicit مشخص شود، conversion بهصورت اتوماتیک انجام خواهد شد. اگر conversion بهصورت explicit تعریف شده، cast مورد نیاز است. نمیتوانید برای یک source-type و target-type هم implicit و explicit را تعریف کنید.
مثال:
class TwoD
{
int X, Y;
public TwoD()
{
X = Y = 0;
}
public TwoD(int a, int b)
{
X = a;
Y = b;
}
public static implicit operator int(TwoD op)
{
return op.X * op.Y;
}
}
// Using :
TwoD ob1 = new TwoD(2, 2);
TwoD ob2 = new T TwoD(1, 1);
int i = ob1 * 3;
Console.WriteLine(i);
i = ob1 - 3;
Console.WriteLine(i);
i = ob1 + ob2;
Console.WriteLine(i);
i = ob1;
Console.WriteLine(i);
نکته:
محدودیتهایی که در conversion operators وجود دارد:
- در Target-type یا source-type در conversion بایستی از جنس همان کلاسی شود که conversion در آن تعریف شده است. برای مثال نمیتوانید تبدیل double به int را از نو تعریف کنید.
- نمیتوانید class type را به نوع دادهی object تبدیل کنید.
- نمیتوانید برای یک source-type و target-type هم تبدیل implicit و هم تبدیل explicit تعریف کنید.
- نمیتوانید از یک base class به یک derived class تبدیل انجام دهید.
- نمیتوانید برای یک class-type به/از interface تبدیل انجام دهید.
- علاوهبر این قوانین، برای انتخاب بین implicit یا explicit باید دقت کنید.
- implicit conversion باید زمانی مورد استفاده قرار گیرد که تبدیل کاملاً عاری از خطا شود
برای کسب اطمینان در این مورد از این دو قانون پیروی کنید:
- هیچ فقدان اطلاعاتی (مثل کوتاهسازی، سرریز، تغییر علامت و…) نباید رخ دهد.
- تبدیل نباید باعث بروز exception یا خطا در برنامه شود. اگر conversion نتواند این دو قانون را رعایت کند، باید از explicit conversion بهره ببرید.
Indexers
index گذاری آرایه از طریق اپراتور [ ] انجام میشود. تعریف کردن اپراتور [ ] برای کلاس نیز امکانپذیر است اما برای این منظور از operator method استفاده نکرده و در عوض از Indexer استفاده میکنیم. Indexer اجازه میدهد یک شیء مانند یک آرایه index گذاری شود. Indexerها میتوانند یک یا بیشتر از یک بعد شوند.
فرم کلی Indexer یک بعدی بهشکل زیر است:
element-type this[int index] {
// The get accessor
get {
// return the value specified by index
}
// The set accessor
set {
// set the value specified by index
}
}
در اینجا، element-type مشخص کنندهی نوع عنصر indexer است. پارامتر index در واقع index عنصری که میخواهید به آن دسترسی پیدا کنید را مشخص میکند. توجه کنید که نیازی نیست حتماْ جنس پارامتر int شود اما استفاده از int در این مورد رایج است. درون بدنهی indexer کلمههای get و set را مشاهده میکنید که به هر کدام از آنها accessor گفته میشود. یک accessor مشابه یک متد است با این تفاوت که return-type و parameter ندارد. هنگامیکه از indexer استفاده میکنید این accessorها بهطور اتوماتیک فراخوانی میشوند. هر دوی accessorها index را بهعنوان پارامتر دریافت میکنند اگر indexer در طرف چپ تساوی قرار بگیرند، set accessor فراخوانی شده و یک مقدار به عنصری که توسط index مشخص شده است، اختصاص داده میشود. در غیر اینصورت get accessor فراخوانی شده و عنصر مشخص شده توسط index، return میشود. Set method یک پارامتر به اسم value دارد که شامل مقداری است که به یک index مشخص اختصاص داده میشود.
مثال:
class IndexerDemo
{
int[] arr; // reference to underlying array (backing store)
public int Lenght;
public IndexerDemo(int size)
{
arr = new int[size];
Lenght = size;
}
// Indexer
public int this[int index]
{
// get accessor
get
{
return arr[index];
}
// set accessor
set
{
arr[index] = value;
}
}
}
// Using :
IndexerDemo ob = new IndexerDemo(4);
ob[0] = 10;
ob[1] = 20;
ob[2] = 30;
ob[3] = 40;
for (int i = 0; i < ob.Lenght; i++)
{
Console.WriteLine(ob[i]);
}
مثال:
برای اینکه این بحث به طور کامل واضح شود در مثال زیر روی get و set کنترل بیشتری اعمال کردهایم:
class IndexerDemo
{
int[] arr;
public int Length;
public bool ErrFlag;
public IndexerDemo(int size)
{
arr = new int[size];
Length = size;
}
public int this[int index]
{
get
{
if (Ok(index))
{
ErrFlag = false;
return arr[index];
}
else
{
ErrFlag = true;
return 0;
}
}
set
{
if (Ok(index))
{
ErrFlag = false;
arr[index] = value;
}
else
{
ErrFlag = true;
}
}
private bool Ok(int index)
{
if (index >= 0 && index < Length)
return true;
return false;
}
}
// Using :
IndexerDemo ob = new IndexerDemo(5);
for (int i = 0; i < 10; i++)
{
ob[i] = i * 10;
if (ob.ErrFlag)
Console.WriteLine("ob[{0}] is out of bound!", i);
else
Console.WriteLine("ob[{0}]: {1}", i, ob[i]);
}
یک کلاس این قابلیت را اضافه کنید تا بهشکل آرایه نیز بتوان از آن استفاده کرد.
به مثال زیر توجه کنید:
class IndexerDemo
{
public int this[int index]
{
get
{
if (index >= 1 && index <= 10)
{
return index * 10;
}
else
return -1;
}
}
}
// Using :
IndexerDemo ob = new IndexerDemo();
Console.WriteLine(ob[1]);
Console.WriteLine(ob[2]);
Console.WriteLine(ob[3]);
Console.WriteLine(ob[11]);
Console.WriteLine(ob[10]);
دو محدودیت دیگر برای Indexerها موجود است:
- بهدلیل اینکه indexerها در واقع storage location (محل ذخیره سازی) تعریف نمیکنند و به نوعی متد هستند. استفاده از آنها بهعنوان پارامتر ref و out غیرمجاز است.
- indexer نمیتواند بهصورت static تعریف شود.
نظرات خود را در ارتباط با “اپراتورها در سی شارپ” برای ما ارسال کنید تا در دورههای بعدی از نظرات شما برای بهبود سایت استفاده کنیم. خب این جلسه هم به پایان رسید باید به این نکته توجه کنید که مباحث بالا در برنامه نویسی تجاری اهمیت فراوانی دارد. برای استفاده از تمامی جلسات از هشتگ #دوره آموزشی_سی_شارپ در سایت ما استفاده کنید. منتظر جلسه ی بعدی دوره آموزشی سی شارپ بمانید.



















آیا میشه برای یه کلاس همزمان چندتا indexer با پارامترهای مختلف تعریف کرد؟
بله، در سیشارپ میتوان برای یک کلاس چند Indexer با امضاهای مختلف (تعداد یا نوع پارامترها) تعریف کرد، چون ایندکسرها هم مانند متدها قابلیت overload دارند. مثلاً میتوانید یک ایندکسر با پارامتر int داشته باشید و یک ایندکسر دیگر با پارامتر string یا حتی چند پارامتر تعریف کنید. این امکان به شما اجازه میدهد دسترسی به دادههای کلاس را با کلیدهای متفاوت یا روشهای متنوع انجام دهید و کد خواناتر و منعطفتری بنویسید. البته هر ایندکسر باید حداقل یک پارامتر داشته باشد و نمیتواند بدون پارامتر باشد.
چه زمانی بهتره از explicit به جای implicit استفاده کنیم؟
از explicit به جای implicit وقتی استفاده میکنیم که تبدیل نوع (type conversion) ممکن است باعث از دست رفتن داده، ایجاد استثناء یا ابهام در معنا شود و بخواهیم برنامهنویس این تبدیل را بهصورت آگاهانه و با نوشتن cast انجام دهد. در این حالت، مجبور شدن به استفاده از (Type) قبل از مقدار باعث میشود که فردی که کد را مینویسد یا میخواند بداند که این تبدیل ممکن است ناایمن باشد یا هزینه خاصی داشته باشد. بهطور مثال، تبدیل double به int یا یک کلاس پایه به یک کلاس مشتق خاص معمولاً explicit تعریف میشود تا جلوی تبدیلهای ناخواسته و خطاهای زمان اجرا گرفته شود، در حالی که implicit بیشتر برای تبدیلهای کاملاً امن و بدون ریسک بهکار میرود.
من قبلا از این قابلیتها در پروژهام استفاده نکرده بودم
خوشحالیم این نوشته مناسب شما بود.
تفاوت بین implicit و explicit خیلی ظریفه
خوشحالیم که این نوشته برای شما مفید بود.
من توی امتحان دانشگاه یه سوال دقیقاً از روی همین نوع تبدیلها داشتم
موفق باشید.