نوع داده‌ی enum و کاربرد آن در یونیتی

نوع داده‌ی enum (که کوتاه‌شده‌ی عبارت Enumeration Type است و اینام خوانده می‌شود) در ساده‌ترین تعریف خود جواب پرسشی است که پاسخ آن تنها می‌تواند یکی از گزینه‌های محدودی باشد که از قبل برای آن پرسش تعریف شده است. پس از تعریف یک enum، می‌توان از روی آن متغیرهایی تعریف کرد که می‌توانند یکی از گزینه‌های پاسخ را به عنوان مقدار در خود ذخیره کنند.

به عنوان مثال یک enum به نام Today را در نظر بگیرید که قصد داریم شماره‌ی روز امروز را در آن قرار دهیم. متغیر این enum که وظیفه‌ی ذخیره‌ی یک روز از هفته را بر عهده دارد تنها می‌تواند یکی از مقادیر شنبه، یک‌شنبه، دوشنبه، سه‌شنبه، چهارشنبه، پنج‌شنبه یا جمعه را در خود ذخیره کند. بدیهی است که روز هفته تنها یکی از گزینه‌های محدود ذکر شده است و حالت دیگری وجود ندارد. در چنین مواردی از نوع داده‌ی enum استفاده می‌کنیم.

image

نمایشی بصری از مفهوم enum؛ این نوع داده بسیار پراستفاده و کاربردی است و به احتمال زیاد تا قبل از آشنایی با enum سروکار زیادی با این نوع داده در برنامه‌های مختلف داشته‌ایم. تصویر فوق یک متغیر enum است که در Inspector یونیتی سریالایز شده است.

نکته

نوع داده‌ی enum از نوع value type است.

تعریف یک enum جدید

برای تعریف یک enum جدید پس از نوشتن کلمه‌ی کلیدی enum و انتخاب یک نام برای آن، تمام گزینه‌های ممکن برای پاسخ را بین آکلاد نوشته و آن‌ها را با ویرگول از هم جدا می‌کنیم. به عنوان مثال برای تعریف enum روزهای هفته چنین می‌کنیم:

enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }
نکته

در تعریف گزینه‌های یک enum از دابل کوتیشن ” در دو طرف آن استفاده نمی‌کنیم (همانند کاری که هنگام نوشتن یک string در کد انجام می‌دادیم). همچنین در هنگام تعریف enum از عملگر تخصیص (=) استفاده نمی‌شود و گذاشتن سمی کالن در آخر تعریف نیز اختیاری است.

طبق قراردادهای نامگذاری، نامگذاری enum باید به صورت PascalCase و به صورت مفرد باشد (مگر در enum های بیتی که از اسم جمع استفاده می شود).

بهتر است در صورتی که گزینه ها اولویت خاصی نسبت به یکدیگر ندارند به ترتیب حروف الفبا نوشته شوند. چرا که در هر صورت اعضای enum در IntelliSense به ترتیب حروف الفبا نمایش داده می شوند که ممکن است گاهی گیج کننده شود.

ایجاد متغیر از روی enum از قبل ساخته شده

در نهایت برای ایجاد متغیر از روی enum ساخته شده و مقداردهی آن از بین گزینه‌های پاسخ (مثلاً گزینه‌ی Sunday در این مثال) از چنین کدی استفاده می‌کنیم:

Day Today = Day.Sunday;

همانطور که مشاهده می‌کنید دسترسی به یک گزینه از بین گزینه‌های ممکن برای پاسخ یک enum با نوشتن نام enum و عملگر نقطه (dot operator) و سپس نوشتن نام گزینه امکان‌پذیر است.

کاربرد enum در یونیتی

این نوع داده در توسعه‌ی بازی کاربردهای فراوانی دارد؛ از جمله استفاده از switch caseها و مواردی که هوش مصنوعی بازی باید از بین چندین الگوریتم یکی را انتخاب کند (مثل یک دشمن NPC که چندین روش حمله به بازیکن برای آن نوشته شده و بسته به شرایط موجود باید یکی از آن‌ها را انتخاب کند).

همچنین فریمورک یونیتی نیز به کرات از این نوع داده استفاده کرده است. برای مثال اینام KeyCode که اختصاصی یونیتی بوده و در آن تمام دکمه‌های صفحه‌کلید و کنترلر کنسول‌ها لیست شده است و در هنگام کدنویسی برای صحبت از یک دکمه‌ی خاص باید از این enum استفاده کرد:

if(Input.GetKeyUp(KeyCode.Escape)){
//Do something
}

جزئیات کار با نوع داده‌ی enum

cast کردن در متغیرهای ساخته شده از روی enumها

در یک enum تعریف شده، گزینه‌هایی که برای آن در نظر گرفته می‌شود در واقع مجموعه‌ای از ثوابت هستند. به هر گزینه به طور پیش‌فرض یک ثابت integer نظیر می‌شود که اولین گزینه نظیر به عدد 0، دومین گزینه نظیر به عدد 1 و تناظر به همین صورت ادامه دارد. با cast کردن نمونه به int می‌توان این عدد را به دست آورد (همچنین برعکس این عمل یعنی cast کردن یک int به نوع enum نیز امکان‌پذیر است):

//Cast Day type to int
int todayToInt = (int)Today;
//Cast int to Day type
int tomorrowInt = 1;
Day Tomorrow = (Day)tomorrowInt;

باید دقت شود که امکان cast کردن enum به string به دلیل قرار نداشتن آن ها در یک سلسله مراتب وراثت وجود ندارد و باید برای این کار از متد ToString (از کلاس Object) استفاده شود.

نکته

cast کردن بیشتر برای تغییر نوع اشاره‌گر به یک شی استفاده می شود و برای به دست آوردن عدد متناظر به نمونه (در صورتی که قرارگیری عدد در string اهمیتی نداشته باشد و برای مثال تنها قصد نمایش آن در Console را داشته باشید) بهتر است از روش جایگزین cast که در ادامه توضیح داده شده است استفاده شود.

استفاده از متد ToString کلاس Object بر روی متغیر ساخته شده از روی enum

استفاده از این متد بدون وارد کردن هرگونه آرگومان، باعث برگشت مقدار در قالب string می‌شود. اما با وارد کردن رشته‌ی "D" در ورودی متد، می‌توان نوع خروجی را به عدد Decimal که در یک string قرار گرفته است تغییر داد:

//Convert Day type to string using ToString() method
string todayToString = Today.ToString(); //Output: "Sunday"
//Convert Day type to decimal using ToString() method and "D" argument which stands for Decimal
//Output is string, but it stores a decimal value
string todayValueToDecimal = Today.ToString("D"); //Output: "0"

دقت کنید که هرچند مقدار نهایی todayValueToDecimal عدد 0 است، اما این عدد در یک string قرار گرفته است و این تفاوت استفاده از cast و متد ToString است.

cast کردن string به گزینه‌ی enum

برای تبدیل string به گزینه‌ی enum باید از کد زیر استفاده نمود که البته کمی پیچیده‌تر است (این string باید از گزینه‌های موجود در enum باشد که در غیر این صورت با exception روبرو می‌شویم):

//Cast string to Day enum
Day Tomorrow = (Day)Enum.Parse(typeof(Day), "Monday");

cast کردن عبارت نهایی به Day به این دلیل است که خروجی متد Parse کلاس Enum همواره یک Object است و برای قرارگیری در فیلد Tomorrow باید به Day تبدیل شود.

تغییر شماره‌های ثوابت گزینه‌های enum از مقادیر پیش‌فرض به مقادیر دلخواه

همانطور که گفته شد شماره‌گذاری اعضای enum به صورت پیش‌فرض از 0 شروع شده و به ترتیب به هر عضو عدد بعدی نظیر می‌شود. اما در این بین می‌توان با گذاشتن علامت مساوی در کنار یک عضو و نوشتن یک شماره (یا یک const هم‌نوع ثابت و یا حتی مقدار یکی دیگر از اعضا با نوشتن نام آن عضو)، این عدد پیش‌فرض را تغییر داد:

enum Day2 { Sunday = 1, Monday = 2, Tuesday = 4, Wednesday = 8, Thursday = 16, Friday, Saturday }

این نوع شماره‌گذاری (دنباله‌ی هندسی با قدرنسبت 2) معمولاً در enumهای بیتی (که خصوصیت [Flags] را دارا هستند) به کار می‌رود.

نکته

در صورتی که در جلوی یک عضو که به صورت دستی شماره‌گذاری شده، عضو یا اعضای دیگری قرار داشته باشند که به صورت دستی شماره‌گذاری نشده باشند، مقدار ثابت پیش‌فرض آن‌ها از مقدار ثابت عضو قبلی (آخرین عضو دستی شماره‌گذاری شده) شروع به شمارش می‌کند (با اضافه شدن یک واحد به مقدار در هر عضو). یعنی در کد بالا مقدار Friday برابر با 17 و مقدار Saturday برابر با 18 خواهد بود.

تغییر نوع ثوابت enumها از نوع پیش‌فرض (int) به سایر انواع

هرچند این قابلیت چندان کاربردی ندارد، اما می‌توان دلایلی نادر مثل کمبود ظرفیت متغیر int را به میان آورد که در این حالت باید ثوابت enum در یک متغیر با محدوده‌ی بیشتر قرار گیرند. انواع مجاز برای این کار عبارتند از:

byte, sbyte, short, ushort, int, uint, long, ulong

برای انجام این کار هنگام تعریف enum، پس از نوشتن نام موردنظر برای enum کاراکتر دونقطه (:) و سپس نوع موردنظر نوشته می‌شود:

enum Day3:uint { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
نکته

امکان استفاده از متدهای توسعه‌یافته برای نمونه‌های ساخته شده‌ی enum وجود ندارد، هرچند می‌توان برای خود نوع Enum از متدهای توسعه‌یافته استفاده کرد. چرا که تمامی enumها از کلاس Enum ارث‌بری می‌کنند (طبق قرارداد سی شارپ enumها همگی sealed هستند و تنها از کلاس Enum ارث‌بری می‌کنند). برخلاف نمونه‌ها، خود کلاس Enum از نوع reference type است.

استفاده از enum در حلقه

یکی از قابلیت‌های جالب enum امکان استفاده از آن به عنوان iteration variable (متغیرهایی که در ساختارهای تکرار استفاده می‌شوند) است. به عنوان مثال داریم:

//Main Method:
for (Day dayInTheLoop = Day.Sunday; dayInTheLoop <= Day.Saturyday; dayInTheLoop++)
{
Console.WriteLine(dayInTheLoop + " is number\t" + (int)dayInTheLoop);
}
/* Output:
* Sunday is number 0
* Monday is number 1
* Tuesday is number 2
* Wednesday is number 3
* Thursday is number 4
* Friday is number 5
* Saturyday is number 6
*/

در این مثال با این که متغیر dayInTheLoop عددی نیست، اما امکان استفاده از آن در حلقه وجود دارد.