خوش برگشتید.
در این ویدیو ما به **Nullable**ها نگاه خواهیم کرد.
و **Nullable**ها یک ابزار واقعا قدرتمند هستند که چند سال پیش به **C#** اضافه شد و چیزیه که من اولین بار وقتی از **Kotlin** استفاده کردم باهاش روبرو شدم، که به اصطلاح یک زبان برنامه نویسی جدیدتر هست، و فکر می‌کنم این ویژگی رو از ابتدا در خودش داشت.
بنابراین **Nullable**ها اساساً متغیرهایی هستند که می‌تونن **Null** باشن. باشه؟
چون متغیرهای معمولی در **C#** نمی‌تونن **Null** باشن. بیایید نگاهی بهش بندازیم.
پس اگه من این **int age** رو داشته باشم، مثلاً، و به اون **null** اختصاص بدم، یک **Compiler Error** می‌گیرم. پس مستقیماً می‌گه: "هی، این کار نمی‌کنه."
"نمی‌تونی این کار رو بکنی چون نمی‌تونی **Null** رو به **int** تبدیل کنی چون اون یک **Non-nullable Value Type** هست."
پس اون یک **Non-nullable Value Type** هست.
چطور می‌تونم اون رو به یک **Nullable Value Type** تبدیل کنم؟
خب، می‌تونم فقط یک علامت سوال بعد از کلمه کلیدی **int** اضافه کنم.
پس حالا این تبدیل به یک **Nullable Value Type** می‌شه.
حالا این تبدیل به یک **Nullable int** می‌شه.
پس **int** علامت سوال یک **Nullable int** هست. **Nullable** به این معنا که قادر به **Null** بودن هست.
اینطوری می‌تونید حفظش کنید.
پس اون **Nullable** هست.
حالا می‌تونم اون رو **Null** کنم.
بیایید چک کنیم که آیا مقداری داره یا نه و بر اساس اون جلو بریم.
پس فرض کنید **age** یک مقدار داره.
اون وقت من می‌نوشتم به کنسول: "**Age** is: " و بعد **age.Value**.
پس چیزی که اینجا می‌بینید اینه که وقتی با **Nullable** کار می‌کنید، می‌تونید به این **Value Property** دسترسی داشته باشید.
همین برای **HasValue** هم صادقه. پس این **HasValue** برمی‌گردونه که آیا متغیری که داریم اون رو اعمال می‌کنیم **Null** هست یا نه.
پس اگه **Null** باشه، اون وقت **HasValue** **False** برمی‌گردونه. و اگه مقداری داشته باشه، **True** برمی‌گردونه.
پس به همین دلیل این دستور **if** اینجا کار می‌کنه.
و بعد این **age.Value** مقدار واقعی اون **age** رو به ما خواهد داد. باشه.
حالا در بلوک **else**، کاری که قراره انجام بدم اینه که فقط می‌نویسم: "**Age** is not specified" (سن مشخص نشده است)، باشه.
پس حالا در مورد ما، قراره بگه: "**Age** is not specified" چون **age** **Null** هست و بنابراین این اجرا نمی‌شه. پس می‌گه: "این **False** هست." بنابراین مستقیماً به بلوک **else** می‌ره.
حالا می‌تونید مستقیماً از **age** استفاده کنید.
این بلافاصله باعث خطا نخواهد شد.
بنابراین می‌تونید مثلاً اینجا **+ age** استفاده کنید. این به طور جالبی باعث خطا نخواهد شد.
و این به دلیل **Type Safety** در **C#** هست.
پس **C#** در موردش بسیار هوشمنده. فقط می‌گه: "خب، می‌دونی چیه؟
من قراره اون رو نادیده بگیرم."
اما اگه سعی کنید کاری انجام بدید که، فرض کنید، **age** مقداری نداشته باشه. پس می‌دونیم که در بلوک **else** **age** مشخص نشده.
پس نمی‌تونستیم جلو بریم. و فرض کنیم یک متغیر دیگه **int myAge = 35** داریم. برای مثال، نمی‌تونم بگم **int sum** قراره **age + myAge** باشه. باشه، این کار نمی‌کنه.
پس باید از **age.Value** استفاده کنیم تا جلو بریم و ازش استفاده کنیم. اما **age.Value** اگه **age** مقداری نداشته باشه، باعث خطا می‌شه.
پس اگه **age** در واقع **Null** باشه، باشه، بیایید این کد رو اجرا کنیم و ببینیم چه خطایی قراره بگیریم.
پس می‌بینید، ما این **System.InvalidOperationException: Nullable object must have a value** رو می‌گیریم که خطاییه که من دارم می‌گیرم. ما فقط زمانی می‌تونیم به **age.Value** دسترسی داشته باشیم که از **HasValue** استفاده کنیم.
و ما فقط می‌تونیم یک **Nullable** رو به یک **Non-nullable** اضافه کنیم اگه در واقع به خود **Value** دسترسی داشته باشیم به جای متغیر.
بنابراین، همانطور که دیدید، ما نمی‌تونیم فقط بگیم **age + myAge** چون می‌گه: "**Cannot implicitly convert int? to int. An explicit conversion exists**." (نمی‌توان به‌طور ضمنی **int?** را به **int** تبدیل کرد. یک تبدیل صریح وجود دارد.) آیا **Cast** را فراموش کرده‌اید؟
و بعد می‌گه: "**Nullable value type may be null**." (نوع مقدار قابل تهی ممکن است **null** باشد.) پس این ممکنه **Null** باشه و به همین دلیله که می‌گه: چک کن آیا مقداری داره، که ما با این دستور **if** انجام دادیم، و فقط بعد از اون این محاسبه رو انجام بده.
بنابراین اگه ما اینجا به جای **HasValue** بگیم **Value**. و بخوایم این محاسبه رو انجام بدیم، می‌تونستیم این کار رو اینجا انجام بدیم.
اینجا کار می‌کرد چون می‌تونیم به **Value** دسترسی داشته باشیم چون **HasValue** قبلاً چک کرده که **age** در واقع **Null** نیست.
پس چیزی که ما داریم می‌گیم اینه که شما نمی‌تونید "هیچی" رو با چیز دیگه‌ای جمع کنید. باید مطمئن بشید که "هیچی" "هیچی" نیست. پس مقداری داره، یعنی در واقع یک **Value** هست. باشه.
پس بیایید به کاربرد در سناریوهای دنیای واقعی نگاه کنیم چون کمی عجیبه، درسته؟ این **Nullable** در مورد چیه؟
خب، قضیه اینه که **Nullable Type**ها به ویژه در سناریوهایی مفید هستند که یک متغیر ممکنه قابل اجرا نباشه. یا جاهایی که مقادیر از دست رفته‌اند، مثلاً در تعاملات پایگاه داده.
بنابراین فیلدهای پایگاه داده ممکنه اگه تنظیم نشده باشند، **Null** برگردونن.
پس فرض کنید ما یک پایگاه داده با **Username**، **Email Address**، **Phone Number** و **Address** کاربر داریم. اما کاربر هرگز شماره تلفن خودش رو وارد نکرده.
پس ناگهان ما یک فیلد **Null** در اونجا داریم و نمی‌تونیم اون رو به روش دیگه‌ای مدیریت کنیم مگر اینکه در واقع قادر به مدیریت **Null**ها یا **Nullable** باشیم و **Nullable**ها برای مدیریت چنین مواردی عالی هستند.
بسیار خب.
و بعد **Form Data** (داده‌های فرم).
بنابراین هنگام کار با فرم‌هایی که کاربران ممکنه همه فیلدها رو ارائه ندن، مثل پاسخ‌های اختیاری نظرسنجی، **Nullable Type**ها می‌تونن نشان بدن که آیا پاسخی داده شده یا نه.
پس این دوباره تقریباً شبیه مثال پایگاه داده‌ای هست که همین الان بهتون دادم.
اما ایده یکسانه.
اساساً ما داده‌ها رو نداریم، پس داده‌ها رو از یک پایگاه داده یا از کاربر یا هر چیز دیگه دریافت نمی‌کنیم.
و اگه اون رو دریافت نکنیم و به درستی مدیریتش نکنیم، اون وقت برنامه‌مون **Crash** می‌کنه. و این چیزیه که می‌خوایم ازش دوری کنیم.
پس مزایای استفاده از **Nullable Type**ها چی می‌تونه باشه؟
خب اول از همه، **Safety** (ایمنی).
بنابراین از خطاهای زمان اجرا جلوگیری می‌کنه که می‌تونه هنگام کار با انواعی که ممکنه مقداری نداشته باشن، رخ بده، همونطور که همین الان در مثال‌های پایگاه داده، و در مثال فرم هم دیدیم. و بعد **Clarity** (وضوح).
بنابراین در کد شما مشخص می‌کنه که یک متغیر ممکنه همیشه مقداری نداشته باشه که قابلیت خوانایی و نگهداری کد رو بهبود می‌بخشه.
و گاهی اوقات می‌بینید که یک متد انتظار یک **Nullable** رو داره.
بنابراین هر وقت داریم با متدهایی کار می‌کنیم که نیاز به **Nullable** دارن، استفاده از اون‌ها هم منطقیه.
بنابراین ما خواهیم دید یا قبلاً دیدیم چند مثال که در اون متد انتظار یک **Nullable** رو داشت، اما همچنین خوب بود که یک **Non-nullable** به عنوان آرگومان داشته باشه. بنابراین این چیزیه که من بیشتر بهتون نشون خواهم داد یا هر بار که در ویدیوهای بعدی باهاش روبرو می‌شیم عمیق‌تر بهش می‌پردازم.