💡 نکته سریع #C :
همه ما با عملگرهای حسابی مثل + و * آشناییم. ولی آیا میدونستید یه نکتهی جالب و مهم در موردشون موقع کار با تایپهای کوچیکی مثل byte و short وجود داره؟
فرض کنید میخواید دو تا byte رو با هم جمع کنید. چه اتفاقی میفته؟
چرا خطا میده؟
چون در #C، وقتی عملیات حسابی روی تایپهای کوچکتر از int (مثل byte یا short) انجام میشه، اونها اول به صورت خودکار به int تبدیل میشن و حاصل عملیات هم یک int خواهد بود!
بنابراین، کد صحیح این شکلیه:
دلیل این کار چیه؟
این رفتار برای بهینهسازی و سادگی در سطح پردازنده و CLR طراحی شده. کار کردن با int (که معمولاً اندازه کلمه پردازنده است) سریعتر و بهینهتره.
حالا اگه حتماً نتیجه رو تو یه byte میخواید چی؟
باید خودتون صراحتاً نتیجه رو کست کنید (و البته حواستون به سرریز شدن یا Overflow باشه!):
حرف آخر: یادتون باشه، حاصل عملیات حسابی روی تایپهای کوچیک، همیشه یه intئه! دونستن همین نکته کوچیک، جلوی خیلی از خطاهای کامپایل ناگهانی رو میگیره.
راز عملگرهای حسابی با تایپهای کوچک!
همه ما با عملگرهای حسابی مثل + و * آشناییم. ولی آیا میدونستید یه نکتهی جالب و مهم در موردشون موقع کار با تایپهای کوچیکی مثل byte و short وجود داره؟
فرض کنید میخواید دو تا byte رو با هم جمع کنید. چه اتفاقی میفته؟
byte b1 = 10;
byte b2 = 20;
// انتظار داریم این کد کار کنه، ولی...
// ❌ این خط کامپایل نمیشه!
byte result = b1 + b2;
چرا خطا میده؟
چون در #C، وقتی عملیات حسابی روی تایپهای کوچکتر از int (مثل byte یا short) انجام میشه، اونها اول به صورت خودکار به int تبدیل میشن و حاصل عملیات هم یک int خواهد بود!
بنابراین، کد صحیح این شکلیه:
// ✅ درسته! حاصل جمع دو بایت، یک int است.
int result = b1 + b2;
دلیل این کار چیه؟
این رفتار برای بهینهسازی و سادگی در سطح پردازنده و CLR طراحی شده. کار کردن با int (که معمولاً اندازه کلمه پردازنده است) سریعتر و بهینهتره.
حالا اگه حتماً نتیجه رو تو یه byte میخواید چی؟
باید خودتون صراحتاً نتیجه رو کست کنید (و البته حواستون به سرریز شدن یا Overflow باشه!):
// ✅ درسته (با مسئولیت خودتان!)
byte result = (byte)(b1 + b2);
حرف آخر: یادتون باشه، حاصل عملیات حسابی روی تایپهای کوچیک، همیشه یه intئه! دونستن همین نکته کوچیک، جلوی خیلی از خطاهای کامپایل ناگهانی رو میگیره.
🔖 هشتگها :
#CSharp
#QuickTip
💣 تلههای کار با اعداد صحیح :
تقسیم، Overflow و checked
فکر میکنید 2÷5 همیشه حاصلش 2.5 میشه؟ یا int.MaxValue + 1 یه عدد خیلی بزرگه؟ اگه جوابتون "بله" هست، این پست برای شماست!
تو دنیای اعداد صحیح، تلههای پنهانی وجود داره که میتونه بیصدا و بدون هیچ هشداری، کدهای شما رو به فنا بده. بزن بریم این خطرات رو بشناسیم و یاد بگیریم چطور ازشون جلوگیری کنیم.
تقسیم، Overflow و checked
فکر میکنید 2÷5 همیشه حاصلش 2.5 میشه؟ یا int.MaxValue + 1 یه عدد خیلی بزرگه؟ اگه جوابتون "بله" هست، این پست برای شماست!
تو دنیای اعداد صحیح، تلههای پنهانی وجود داره که میتونه بیصدا و بدون هیچ هشداری، کدهای شما رو به فنا بده. بزن بریم این خطرات رو بشناسیم و یاد بگیریم چطور ازشون جلوگیری کنیم.
🔪 تله اول: تقسیم صحیح و سلاخی اعشار!
وقتی دو عدد صحیح رو بر هم تقسیم میکنید، سی شارپ بخش اعشاری حاصل رو گرد نمیکنه، بلکه به سادگی حذف (Truncate) میکنه.
این یعنی نتیجهی تقسیم، همیشه یه عدد صحیحه.
int a = 5;
int b = 2;
// انتظار داریم حاصل 2.5 باشه، ولی اعشار حذف میشه!
int result = a / b;
Console.WriteLine(result); // خروجی: 2
نکته حرفهای: تقسیم بر متغیر صفر
int x=0;
5/x;
باعث خطای زمان اجرا(DivideByZeroException) میشه، ولی تقسیم بر خودِ صفر لیترال ;5/0 باعث خطای زمان کامپایل میشه!
👻 تله دوم (و خطرناکترین) :
سرریز شدن سایلنت (Silent Overflow)
این یکی کابوس برنامهنویسهاست! تصور کنید کیلومترشمار یه ماشین قدیمی بعد از اینکه به 999999 میرسه، دوباره صفر میشه. اعداد صحیح هم به صورت پیشفرض دقیقاً همین رفتار رو دارن!
اگه یه عملیات حسابی از حداکثر ظرفیت یه نوع داده بیشتر بشه، هیچ خطایی رخ نمیده! نتیجه به صورت سایلنت به ابتدای محدوده برمیگرده (Wraparound).
int i = int.MaxValue; // بزرگترین عدد ممکن برای int (حدود ۲ میلیارد)
i = i + 1; // یک واحد بهش اضافه میکنیم
// انتظار داریم خطا بده یا یه عدد بزرگتر بشه، ولی...
// عدد از ماکسیمم به مینیمم جهش میکنه!
Console.WriteLine(i == int.MinValue); // خروجی: True!
این رفتار سایلنت میتونه باعث ایجاد باگهای منطقی بسیار خطرناک و غیرقابل ردیابی در محاسبات مالی، علمی و امنیتی بشه.
🛡 راه نجات :
خوشبختانه، #C راه حل این فاجعه سایلنت رو در اختیار ما گذاشته.
هر عبارتی که داخل checked قرار بگیره، در صورت سرریز شدن، به جای رفتار سایلنت، یک خطای واضح و مشخص به نام OverflowException پرتاب میکنه.
نکته حرفهای: میتونید این قابلیت رو در تنظیمات پروژه برای کل برنامه فعال کنید و هرجا که خواستید رفتار سایلنت رو داشته باشید، از unchecked استفاده کنید.
و اما unchecked: وقتی میخوایم خطر کنیم!
🤔 حرف حساب و تجربه شما
شناختن این رفتارها و استفاده از checked، مرز بین کدنویسی آماتور و حرفهایه.
فرشته نگهبان به نام checked
خوشبختانه، #C راه حل این فاجعه سایلنت رو در اختیار ما گذاشته.
اپراتور checked.
هر عبارتی که داخل checked قرار بگیره، در صورت سرریز شدن، به جای رفتار سایلنت، یک خطای واضح و مشخص به نام OverflowException پرتاب میکنه.
int a = 1_000_000;
int b = 1_000_000;
try
{
// این عبارت رو برای سرریز شدن چک کن
// حاصل ضرب از ظرفیت int بیشتر میشه
int c = checked(a * b); // اینجا استثنا (Exception) رخ میده!
Console.WriteLine(c);
}
catch (OverflowException)
{
Console.WriteLine("Overflow detected! Calculation aborted.");
}
نکته حرفهای: میتونید این قابلیت رو در تنظیمات پروژه برای کل برنامه فعال کنید و هرجا که خواستید رفتار سایلنت رو داشته باشید، از unchecked استفاده کنید.
و اما unchecked: وقتی میخوایم خطر کنیم!
int x = int.MaxValue;
// این عملیات چک نمیشه و به حالت سایلنت برمیگرده
int y = unchecked(x + 1);
unchecked
{
// تمام عبارات این بلوک هم چک نمیشن
int z = x + 1;
}
🤔 حرف حساب و تجربه شما
شناختن این رفتارها و استفاده از checked، مرز بین کدنویسی آماتور و حرفهایه.
🔖 هشتگها :
#CSharp
#DotNet
#Bugs
💡 نکته سریع #C :
یکی از سوالای کلاسیک و در عین حال فنی تو مصاحبههای سیشارپ، تفاوت بین ++x (حالت Postfix) و x++ (حالت Prefix) هست.
هر دوتاشون در نهایت مقدار x رو یکی زیاد میکنن، ولی "زمان" این افزایش، زمین تا آسمون با هم فرق میکنه و همین میتونه رفتار کد شما رو کاملاً عوض کنه.
در این حالت، اول مقدار فعلی و قدیمی x در عبارت استفاده میشه و بعد از اینکه اون خط تموم شد، مقدار x یکی زیاد میشه.
فکر کنید x یه چک بانکیه. شما اول چک رو با همون مبلغ فعلی به طرف میدین (مقدار رو برمیگردونین)، بعد که کارتون تموم شد، تو حساب خودتون یکی بهش اضافه میکنید.
مثال:
اینجا برعکسه. اول مقدار x یکی زیاد میشه و بعد، مقدار جدید و افزایشیافته در عبارت استفاده میشه.
اینجا شما اول تو حساب خودتون یکی به مبلغ چک اضافه میکنید، بعد چک جدید رو با مبلغ افزایشیافته به طرف میدین (مقدار جدید رو برمیگردونین).
مثال:
حرف آخر:
اول مقدار فعلی رو برمیگردونه، بعد x رو آپدیت میکنه.
اول x رو آپدیت میکنه، بعد مقدار جدید رو برمیگردونه.
دونستن همین نکته کوچیک، به خصوص در حلقهها و محاسبات پیچیده، خیلی به کار میاد و جلوی باگهای منطقی رو میگیره!
تفاوت ++x و x++ چیه؟
یکی از سوالای کلاسیک و در عین حال فنی تو مصاحبههای سیشارپ، تفاوت بین ++x (حالت Postfix) و x++ (حالت Prefix) هست.
هر دوتاشون در نهایت مقدار x رو یکی زیاد میکنن، ولی "زمان" این افزایش، زمین تا آسمون با هم فرق میکنه و همین میتونه رفتار کد شما رو کاملاً عوض کنه.
حالت Postfix (اول بده، بعداً زیاد کن!):++x
در این حالت، اول مقدار فعلی و قدیمی x در عبارت استفاده میشه و بعد از اینکه اون خط تموم شد، مقدار x یکی زیاد میشه.
فکر کنید x یه چک بانکیه. شما اول چک رو با همون مبلغ فعلی به طرف میدین (مقدار رو برمیگردونین)، بعد که کارتون تموم شد، تو حساب خودتون یکی بهش اضافه میکنید.
مثال:
int x = 5;
// اینجا اول مقدار فعلی x (یعنی 5) چاپ میشه
Console.WriteLine(x++); // خروجی: 5
// حالا که خط بالا تموم شد، x یکی زیاد شده
Console.WriteLine(x); // خروجی: 6
حالت Prefix (اول زیاد کن، بعداً بده!): x++
اینجا برعکسه. اول مقدار x یکی زیاد میشه و بعد، مقدار جدید و افزایشیافته در عبارت استفاده میشه.
اینجا شما اول تو حساب خودتون یکی به مبلغ چک اضافه میکنید، بعد چک جدید رو با مبلغ افزایشیافته به طرف میدین (مقدار جدید رو برمیگردونین).
مثال:
int y = 5;
// اینجا اول y یکی زیاد میشه (میشه 6)، بعد مقدار جدیدش چاپ میشه
Console.WriteLine(++y); // خروجی: 6
// y که قبلاً زیاد شده بود، هنوز همون 6 هست
Console.WriteLine(y); // خروجی: 6
حرف آخر:
x++ (Postfix):
اول مقدار فعلی رو برمیگردونه، بعد x رو آپدیت میکنه.
++x (Prefix):
اول x رو آپدیت میکنه، بعد مقدار جدید رو برمیگردونه.
دونستن همین نکته کوچیک، به خصوص در حلقهها و محاسبات پیچیده، خیلی به کار میاد و جلوی باگهای منطقی رو میگیره!
🔖 هشتگها :
#CSharp
#QuickTip
#DotNet
🌀 دنیای عجیب اعداد اعشاری: Infinity، NaN و تلههای مقایسه!
فکر میکنید تقسیم بر صفر همیشه خطا میده؟ یا یه مقدار همیشه با خودش برابره؟ تو دنیای اعداد اعشاری (float و double)، قوانین فیزیک یه جور دیگهست!
برخلاف اعداد صحیح، این نوعها مقادیر ویژهای دارن که برای مدیریت شرایط خاص ریاضی طراحی شدن. بیاید باهاشون آشنا بشیم.
فکر میکنید تقسیم بر صفر همیشه خطا میده؟ یا یه مقدار همیشه با خودش برابره؟ تو دنیای اعداد اعشاری (float و double)، قوانین فیزیک یه جور دیگهست!
برخلاف اعداد صحیح، این نوعها مقادیر ویژهای دارن که برای مدیریت شرایط خاص ریاضی طراحی شدن. بیاید باهاشون آشنا بشیم.
♾️ بینهایت (Infinity):
وقتی تقسیم بر صفر خطا نیست!
در دنیای اعداد صحیح، تقسیم بر صفر یه گناه نابخشودنیه و باعث خطای DivideByZeroException میشه. اما در دنیای اعداد اعشاری، اینطور نیست!
تقسیم یک عدد غیرصفر بر صفر، منجر به تولید بینهایت مثبت یا منفی میشه و برنامه به کارش ادامه میده.
این رفتار در محاسبات علمی و گرافیکی که با حدود و مقادیر خیلی بزرگ سر و کار داریم، بسیار مفیده.
وقتی تقسیم بر صفر خطا نیست!
در دنیای اعداد صحیح، تقسیم بر صفر یه گناه نابخشودنیه و باعث خطای DivideByZeroException میشه. اما در دنیای اعداد اعشاری، اینطور نیست!
تقسیم یک عدد غیرصفر بر صفر، منجر به تولید بینهایت مثبت یا منفی میشه و برنامه به کارش ادامه میده.
Console.WriteLine(1.0 / 0.0); // خروجی: Infinity
Console.WriteLine(-1.0 / 0.0); // خروجی: -Infinity
Console.WriteLine(1.0 / -0.0); // خروجی: -Infinity
این رفتار در محاسبات علمی و گرافیکی که با حدود و مقادیر خیلی بزرگ سر و کار داریم، بسیار مفیده.
❓ پوچی مطلق (NaN):
وقتی جواب "عدد نیست"!
مثلاً تقسیم صفر بر صفر، یا کم کردن بینهایت از بینهایت، جوابی نداره و سیشارپ به جای خطا دادن، حاصل رو NaN برمیگردونه.
مثل یه پرچمه که میگه "من نتونستم این محاسبه رو انجام بدم، ولی نذاشتم برنامه کرش کنه".
وقتی جواب "عدد نیست"!
NaN مخفف "Not a Number" (عدد نیست) هست. این مقدار ویژه، حاصل عملیات ریاضی تعریف نشده یا نامعتبره.
مثلاً تقسیم صفر بر صفر، یا کم کردن بینهایت از بینهایت، جوابی نداره و سیشارپ به جای خطا دادن، حاصل رو NaN برمیگردونه.
Console.WriteLine(0.0 / 0.0); // خروجی: NaN
Console.WriteLine((1.0 / 0.0) - (1.0 / 0.0)); // خروجی: NaN
NaN
مثل یه پرچمه که میگه "من نتونستم این محاسبه رو انجام بدم، ولی نذاشتم برنامه کرش کنه".
🪤 تله بزرگ: NaN == NaN همیشه False است!
این یکی از عجیبترین و مهمترین نکاتیه که باید بدونید. طبق استاندارد IEEE 754، یک مقدار NaN هیچوقت با هیچ مقدار دیگهای، حتی یک NaN دیگه، برابر نیست!
منطقش اینه که یک "مقدار نامشخص" نمیتونه با یک "مقدار نامشخص" دیگه برابر باشه.
پس اگه بخواید با == چک کنید که آیا متغیری NaN هست یا نه، همیشه جواب false میگیرید و این میتونه باعث باگهای خیلی بدی بشه.
این یکی از عجیبترین و مهمترین نکاتیه که باید بدونید. طبق استاندارد IEEE 754، یک مقدار NaN هیچوقت با هیچ مقدار دیگهای، حتی یک NaN دیگه، برابر نیست!
منطقش اینه که یک "مقدار نامشخص" نمیتونه با یک "مقدار نامشخص" دیگه برابر باشه.
// این کد شما رو به اشتباه میندازه!
Console.WriteLine(0.0 / 0.0 == double.NaN); // خروجی: False
پس اگه بخواید با == چک کنید که آیا متغیری NaN هست یا نه، همیشه جواب false میگیرید و این میتونه باعث باگهای خیلی بدی بشه.
✅ راه حل: پس چطور NaN رو چک کنیم؟
راه درست و تنها راه مطمئن برای چک کردن NaN، استفاده از متدهای استاتیک double.IsNaN() یا float.IsNaN() هست.
🤔 حرف حساب و تجربه شما
درک این مقادیر ویژه، شما رو از خیلی از باگهای محاسباتی پنهان نجات میده.
شما تا حالا تو محاسباتتون به Infinity یا NaN برخوردید؟ یا از تله مقایسه NaN خبر داشتید؟ این رفتار عجیب اعداد اعشاری کجا به کارتون اومده یا براتون دردسر ساخته؟
تجربههاتون رو کامنت کنید! 👇
راه درست و تنها راه مطمئن برای چک کردن NaN، استفاده از متدهای استاتیک double.IsNaN() یا float.IsNaN() هست.
double result = 0.0 / 0.0;
// روش اشتباه
if (result == double.NaN) { /* این کد هرگز اجرا نمیشه */ }
// روش درست
if (double.IsNaN(result))
{
Console.WriteLine("The result is indeed NaN!");
}
🤔 حرف حساب و تجربه شما
درک این مقادیر ویژه، شما رو از خیلی از باگهای محاسباتی پنهان نجات میده.
شما تا حالا تو محاسباتتون به Infinity یا NaN برخوردید؟ یا از تله مقایسه NaN خبر داشتید؟ این رفتار عجیب اعداد اعشاری کجا به کارتون اومده یا براتون دردسر ساخته؟
تجربههاتون رو کامنت کنید! 👇
🔖 هشتگها :
#CSharp
#CodingTips
#DotNet
#FloatingPoint
#NaN
🎭 تلههای برابری (==) در #C:
مقایسه مقدار در برابر مقایسه آدرس!
فکر میکنید اپراتور == همیشه مقادیر رو با هم مقایسه میکنه؟ اگه دو تا شیء داشته باشیم که محتوای داخلیشون یکسانه، آیا با هم برابرن؟
جواب تو سیشارپ همیشه "بله" نیست! این یکی از اون تلههای کلاسیکه که ریشهش مستقیم به تفاوت Value Type و Reference Type برمیگرده. بیاید این موضوع مهم رو یک بار برای همیشه روشن کنیم.
✅ دنیای ساده: مقایسه Value Typeها
برای Value Typeها (مثل int, struct, bool)، اپراتور == دقیقاً همون کاری رو میکنه که انتظار دارید: مقدار واقعی داخل متغیرها رو با هم مقایسه میکنه. ساده و قابل پیشبینی.
مقایسه مقدار در برابر مقایسه آدرس!
فکر میکنید اپراتور == همیشه مقادیر رو با هم مقایسه میکنه؟ اگه دو تا شیء داشته باشیم که محتوای داخلیشون یکسانه، آیا با هم برابرن؟
جواب تو سیشارپ همیشه "بله" نیست! این یکی از اون تلههای کلاسیکه که ریشهش مستقیم به تفاوت Value Type و Reference Type برمیگرده. بیاید این موضوع مهم رو یک بار برای همیشه روشن کنیم.
✅ دنیای ساده: مقایسه Value Typeها
برای Value Typeها (مثل int, struct, bool)، اپراتور == دقیقاً همون کاری رو میکنه که انتظار دارید: مقدار واقعی داخل متغیرها رو با هم مقایسه میکنه. ساده و قابل پیشبینی.
int x = 5;
int y = 10;
int z = 5;
// آیا مقدار x با y برابره؟ نه.
Console.WriteLine(x == y); // خروجی: False
// آیا مقدار x با z برابره؟ بله.
Console.WriteLine(x == z); // خروجی: True
❓ دنیای پیچیده:
اینجاست که داستان جالب میشه! برای Reference Typeها (مثل class)، اپراتور == به صورت پیشفرض، محتوای داخلی آبجکتها رو مقایسه نمیکنه.
در عوض، آدرس اونها در حافظه رو مقایسه میکنه. یعنی از خودش میپرسه: "آیا این دو متغیر، به یک آبجکت یکسان در حافظه اشاره میکنن؟"
یادتونه گفتیم Reference Type مثل کلید یه خونهست؟ اینجا == چک نمیکنه که آیا دو تا خونه دکوراسیون یکسانی دارن یا نه. فقط چک میکنه که آیا این دو تا کلید، برای یک خونهی یکسان هستن یا برای دو تا خونهی جدا که فقط شبیه هم ساخته شدن.
مثال کلاس Dude رو ببینید:
مقایسه Reference Typeها
اینجاست که داستان جالب میشه! برای Reference Typeها (مثل class)، اپراتور == به صورت پیشفرض، محتوای داخلی آبجکتها رو مقایسه نمیکنه.
در عوض، آدرس اونها در حافظه رو مقایسه میکنه. یعنی از خودش میپرسه: "آیا این دو متغیر، به یک آبجکت یکسان در حافظه اشاره میکنن؟"
یادتونه گفتیم Reference Type مثل کلید یه خونهست؟ اینجا == چک نمیکنه که آیا دو تا خونه دکوراسیون یکسانی دارن یا نه. فقط چک میکنه که آیا این دو تا کلید، برای یک خونهی یکسان هستن یا برای دو تا خونهی جدا که فقط شبیه هم ساخته شدن.
مثال کلاس Dude رو ببینید:
public class Dude
{
public string Name;
public Dude(string n) { Name = n; }
}
// ...
// ما دو تا آبجکت جداگانه در حافظه میسازیم که هر دو اسمشون "John" هست
Dude d1 = new Dude("John");
Dude d2 = new Dude("John");
// اینجا d3 کلید خونهی d1 رو میگیره، خونه جدیدی ساخته نمیشه
Dude d3 = d1;
// آیا d1 و d2 به یک آبجکت یکسان اشاره میکنند؟ نه!
// (دو تا خونه جدا ولی شبیه به هم)
Console.WriteLine(d1 == d2); // خروجی: False
// آیا d1 و d3 به یک آبجکت یکسان اشاره میکنند؟ بله!
// (دو تا کلید برای یک خونه)
Console.WriteLine(d1 == d3); // خروجی: True
🪄 جادوی اپراتورهای شرطی #C :
از Short-Circuiting تا اپراتور سهتایی.
فقط یه if ساده نوشتن، کار هر کسیه. اما یه برنامهنویس حرفهای، با استفاده از ابزارهایی مثل Short-Circuiting و اپراتور سهتایی، ifهای هوشمندتر، امنتر و خواناتری مینویسه.
بیاید با این جادوهای پرکاربرد آشنا بشیم.
از Short-Circuiting تا اپراتور سهتایی.
فقط یه if ساده نوشتن، کار هر کسیه. اما یه برنامهنویس حرفهای، با استفاده از ابزارهایی مثل Short-Circuiting و اپراتور سهتایی، ifهای هوشمندتر، امنتر و خواناتری مینویسه.
بیاید با این جادوهای پرکاربرد آشنا بشیم.
🔌 اتصال کوتاه (Short-Circuiting):
ناجی شما از NullReferenceException
این مهمترین مفهومیه که در مورد اپراتورهای && (AND) و || (OR) باید بدونید.
در یک عبارت &&، اگر قسمت اول false باشه، #C اونقدر هوشمنده که دیگه قسمت دوم رو اصلاً بررسی نمیکنه (چون نتیجه کل عبارت قطعاً false هست).
در یک عبارت ||، اگر قسمت اول true باشه، باز هم قسمت دوم بررسی نمیشه (چون نتیجه کل عبارت قطعاً true هست).
این فقط برای سرعت بیشتر نیست، بلکه یه تکنیک حیاتی برای جلوگیری از خطاست. به این مثال طلایی نگاه کنید:
اینجا چون myString != null برابر با false هست، #C هیچوقت به myString.Length نگاه هم نمیکنه و برنامه شما از یک خطای حتمی نجات پیدا میکنه!
ناجی شما از NullReferenceException
این مهمترین مفهومیه که در مورد اپراتورهای && (AND) و || (OR) باید بدونید.
قانون اتصال کوتاه میگه:
در یک عبارت &&، اگر قسمت اول false باشه، #C اونقدر هوشمنده که دیگه قسمت دوم رو اصلاً بررسی نمیکنه (چون نتیجه کل عبارت قطعاً false هست).
در یک عبارت ||، اگر قسمت اول true باشه، باز هم قسمت دوم بررسی نمیشه (چون نتیجه کل عبارت قطعاً true هست).
این فقط برای سرعت بیشتر نیست، بلکه یه تکنیک حیاتی برای جلوگیری از خطاست. به این مثال طلایی نگاه کنید:
string myString = null;
// این کد بدون اتصال کوتاه، خطای NullReferenceException میداد
// چون sb.Length روی یک متغیر null اجرا میشد.
if (myString != null && myString.Length > 0)
{
Console.WriteLine("String has content.");
}
else
{
Console.WriteLine("String is null or empty.");
}
اینجا چون myString != null برابر با false هست، #C هیچوقت به myString.Length نگاه هم نمیکنه و برنامه شما از یک خطای حتمی نجات پیدا میکنه!
✨ اپراتور سهتایی (Ternary Operator ? : )
یک if-else در یک خط!
اپراتور سهتایی یه راه خیلی شیک و کوتاه برای نوشتن یه if-else سادهست که قراره یه مقداری رو برگردونه.
ساختارش اینه:
شرط ? مقدار در صورت درستی : مقدار در صورت نادرستی
مثلاً به جای اینکه اینجوری بنویسیم:
میتونیم خیلی شیک و کوتاه اینجوری بنویسیم:
یک if-else در یک خط!
اپراتور سهتایی یه راه خیلی شیک و کوتاه برای نوشتن یه if-else سادهست که قراره یه مقداری رو برگردونه.
ساختارش اینه:
شرط ? مقدار در صورت درستی : مقدار در صورت نادرستی
مثلاً به جای اینکه اینجوری بنویسیم:
int a = 10;
int b = 20;
int max;
if (a > b)
{
max = a;
}
else
{
max = b;
}
میتونیم خیلی شیک و کوتاه اینجوری بنویسیم:
int a = 10;
int b = 20;
int max = (a > b) ? a : b; // اگر a > b درست بود، a رو برگردون، وگرنه b رو
Console.WriteLine(max); // خروجی: 20
💡 نکته سریع #C :
سه راز در مورد bool که شاید نمیدانستید!
همه ما هر روز از bool برای شرطهامون استفاده میکنیم، ولی این نوع داده منطقی، چند تا راز کوچک و جالب داره که دونستنشون دید شما رو به سیشارپ عمیقتر میکنه.
برخلاف بعضی زبانهای برنامهنویسی دیگه، در C# نوع bool یک نوع منطقی کاملاً مستقله و هیچ ارتباطی با اعداد نداره. شما نمیتونید یک bool رو به int تبدیل کنید یا برعکس. true معادل 1 نیست!
این ویژگی، جلوی بسیاری از خطاهای منطقی ناخواسته رو میگیره.
سه راز در مورد bool که شاید نمیدانستید!
همه ما هر روز از bool برای شرطهامون استفاده میکنیم، ولی این نوع داده منطقی، چند تا راز کوچک و جالب داره که دونستنشون دید شما رو به سیشارپ عمیقتر میکنه.
بولین، عدد نیست!
برخلاف بعضی زبانهای برنامهنویسی دیگه، در C# نوع bool یک نوع منطقی کاملاً مستقله و هیچ ارتباطی با اعداد نداره. شما نمیتونید یک bool رو به int تبدیل کنید یا برعکس. true معادل 1 نیست!
// این کدها اصلاً کامپایل نمیشن!
// int myInt = (int)true; // ❌ خطای کامپایل!
// bool myBool = (bool)1; // ❌ خطای کامپایل!
این ویژگی، جلوی بسیاری از خطاهای منطقی ناخواسته رو میگیره.
یک بیت یا یک بایت؟ مسئله این است!
از نظر تئوری، برای ذخیره یک مقدار bool (true یا false) فقط یک بیت حافظه کافیه. اما در عمل، CLR برای بهینگی و راحتی کار با پردازنده، برای هر متغیر bool یک بایت (۸ بیت) کامل در حافظه در نظر میگیره.
نکته حرفهای:
اگه نیاز دارید تعداد خیلی خیلی زیادی bool رو در حافظه ذخیره کنید و فضا براتون مهمه (مثلاً در کار با فایلهای باینری)، میتونید از کلاس System.Collections.BitArray استفاده کنید که برای هر مقدار، دقیقاً یک بیت مصرف میکنه.
bool فقط یک نام مستعاره!
مثل بقیه انواع داده پیشساخته، کلمه کلیدی bool در #C فقط یک نام مستعار (alias) ساده و راحت برای نوع داده اصلی در فریمورک داتنت یعنی System.Boolean هست.
این دو خط کد، در نهایت یک کار یکسان رو انجام میدن:
bool b1 = true;
System.Boolean b2 = true; // این همون بالاییه، فقط با اسم کاملش!
حرف آخر:
پس یادتون باشه: bool یه نوع منطقی خالصه، نه یه عدد. در حافظه یه بایت جا میگیره و فقط یه نام مستعار برای System.Boolean هست!
🔖 هشتگها :
#CSharp
#QuickTip
#DotNet
#Boolean
#CodingTips
🔒 رازهای string در #C :
همهی ما هر روز با string کار میکنیم، ولی دو تا از بزرگترین رازهای رفتاریش رو میدونید؟ stringها در سیشارپ هم تغییرناپذیرن و هم اپراتور == روشون یه رفتار خاص داره.
درک این دو نکته، دید شما رو به زبان #C و نحوه مدیریت حافظه، عمیقتر میکنه و شما رو به یه توسعهدهنده مسلطتر تبدیل میکنه.
1️⃣ راز اول:
وقتی یه string میسازید، دیگه هرگز نمیتونید محتوای اون رو در حافظه تغییر بدید. هر عملیاتی که به نظر میاد داره یه string رو عوض میکنه (مثل ToUpper() یا +)، در واقع داره یه string کاملاً جدید در حافظه میسازه و قبلی رو دستنخورده رها میکنه.
مثال:
چرا این ویژگی خوبه؟
این ویژگی باعث میشه کد شما قابل پیشبینیتر، امنتر (به خصوص در محیطهای چندنخی یا Multi-threaded) و بهینهتر باشه، چون کامپایلر میتونه رشتههای یکسان رو در حافظه به اشتراک بذاره (به این کار String Interning میگن).
2️⃣راز دوم:
تو پست "تلههای برابری" دیدیم که == روی Reference Typeها، آدرس حافظه رو مقایسه میکنه. string هم یه Reference Type هست، پس چرا این کد true برمیگردونه؟
جواب:
چون تیم طراح #C اپراتور == رو برای string به صورت خاص بازنویسی (Overload) کرده. اونها میدونستن که ۹۹٪ مواقع وقتی دو تا رشته رو مقایسه میکنیم، منظورمون مقایسه محتوای اونهاست، نه آدرس حافظهشون. پس این اپراتور رو هوشمند کردن تا کار ما رو راحتتر کنن و جلوی یه باگ رایج رو بگیرن!
این یکی از نمونههای طراحی هوشمندانه در زبان #C هست.
🤔 حرف حساب و تجربه شما
این رفتارهای خاص string، نمونهای عالی از طراحی هوشمندانه در زبان #C هست که هم به کارایی کمک میکنه و هم جلوی خطاهای رایج رو میگیره.
آیا تا حالا به این فکر کرده بودید که وقتی یه رشته رو با + ترکیب میکنید، در واقع دارید رشتههای جدید در حافظه میسازید (که میتونه روی پرفورمنس تاثیر بذاره)؟ یا از رفتار خاص == برای string خبر داشتید؟
تغییرناپذیری (Immutability) و جادوی برابری
همهی ما هر روز با string کار میکنیم، ولی دو تا از بزرگترین رازهای رفتاریش رو میدونید؟ stringها در سیشارپ هم تغییرناپذیرن و هم اپراتور == روشون یه رفتار خاص داره.
درک این دو نکته، دید شما رو به زبان #C و نحوه مدیریت حافظه، عمیقتر میکنه و شما رو به یه توسعهدهنده مسلطتر تبدیل میکنه.
1️⃣ راز اول:
🛡تغییرناپذیری (Immutability):
وقتی یه string میسازید، دیگه هرگز نمیتونید محتوای اون رو در حافظه تغییر بدید. هر عملیاتی که به نظر میاد داره یه string رو عوض میکنه (مثل ToUpper() یا +)، در واقع داره یه string کاملاً جدید در حافظه میسازه و قبلی رو دستنخورده رها میکنه.
مثال:
string s1 = "hello";
// این کد s1 را تغییر نمیدهد!
// بلکه یک رشته جدید ("HELLO") میسازد و در s2 قرار میدهد.
string s2 = s1.ToUpper();
Console.WriteLine($"s1: {s1}"); // خروجی: s1: hello
Console.WriteLine($"s2: {s2}"); // خروجی: s2: HELLO
چرا این ویژگی خوبه؟
این ویژگی باعث میشه کد شما قابل پیشبینیتر، امنتر (به خصوص در محیطهای چندنخی یا Multi-threaded) و بهینهتر باشه، چون کامپایلر میتونه رشتههای یکسان رو در حافظه به اشتراک بذاره (به این کار String Interning میگن).
2️⃣راز دوم:
🎭جادوی برابری (==)
تو پست "تلههای برابری" دیدیم که == روی Reference Typeها، آدرس حافظه رو مقایسه میکنه. string هم یه Reference Type هست، پس چرا این کد true برمیگردونه؟
string a = "test";
string b = "test";
Console.WriteLine(a == b); // خروجی: True! ولی چرا؟
جواب:
چون تیم طراح #C اپراتور == رو برای string به صورت خاص بازنویسی (Overload) کرده. اونها میدونستن که ۹۹٪ مواقع وقتی دو تا رشته رو مقایسه میکنیم، منظورمون مقایسه محتوای اونهاست، نه آدرس حافظهشون. پس این اپراتور رو هوشمند کردن تا کار ما رو راحتتر کنن و جلوی یه باگ رایج رو بگیرن!
این یکی از نمونههای طراحی هوشمندانه در زبان #C هست.
🤔 حرف حساب و تجربه شما
این رفتارهای خاص string، نمونهای عالی از طراحی هوشمندانه در زبان #C هست که هم به کارایی کمک میکنه و هم جلوی خطاهای رایج رو میگیره.
آیا تا حالا به این فکر کرده بودید که وقتی یه رشته رو با + ترکیب میکنید، در واقع دارید رشتههای جدید در حافظه میسازید (که میتونه روی پرفورمنس تاثیر بذاره)؟ یا از رفتار خاص == برای string خبر داشتید؟
🔖 هشتگها :
#CSharp
#String
#BestPractices
🛠 نوشتن string مثل یک حرفهای:
در سیشارپ، فقط یک راه برای نوشتن رشتهها وجود نداره. ابزارهای مختلفی در اختیار ماست که هر کدوم برای یه سناریوی خاص، بهترین انتخابه. تسلط بر این ابزارها، کد شما رو نه تنها خواناتر، که حرفهایتر هم میکنه.
1️⃣ روش کلاسیک: دردسرهای Escape Sequence (\)
این روش سنتیترین راهه. برای رشتههای ساده خوبه، ولی وقتی پای کاراکترهای خاص مثل بکاسلش (\) یا کوتیشن (") وسط بیاد، کد شما به سرعت زشت و ناخوانا میشه.
به خصوص برای مسیر فایلها در ویندوز، این روش یه کابوس واقعیه!
2️⃣ راه حل تمیز: Verbatim Literals (@)
اینجاست که @ مثل یه قهرمان وارد میشه! با گذاشتن یه @ قبل از رشته، شما به کامپایلر میگید: "هرچیزی که داخل این رشته هست رو دقیقاً همونطور که هست در نظر بگیر و هیچ کاراکتری رو escape نکن."
این قابلیت دو تا مزیت بزرگ داره:
مسیرهای خوانا:
متنهای چند خطی:
میتونید به راحتی و بدون نیاز به \n، متنهای چند خطی بنویسید.
3️⃣ قدرت مدرن: Raw String Literals ("""...""") (از C# 11 به بعد)
این جدیدترین و قدرتمندترین ابزار ماست که برای حل مشکلات کار با JSON، XML، HTML یا هر متن پیچیدهای طراحی شده.
رشته رو بین سه تا (یا بیشتر) دابل کوتیشن میذارید و دیگه هیچ نیازی به هیچگونه escape کردنی ندارید. حتی لازم نیست " رو دو بار بنویسید!
این قابلیت، کد شما رو به شکل چشمگیری تمیزتر و قابل نگهداریتر میکنه، به خصوص وقتی با متنهای ساختاریافته سر و کار دارید.
🤔 حرف حساب و ابزار شما
هر کدوم از این ابزارها، برای یه کاری ساخته شدن.
●برای رشتههای ساده ⟵ روش کلاسیک
●برای مسیر فایل و متنهای چند خطی ⟵ Verbatim (@)
●برای JSON، XML و متنهای پیچیده ⟵ Raw String (""")
شما از کدوم یکی از این روشها بیشتر استفاده میکنید؟ آیا از طرفدارای Raw String Literals جدید هستید یا هنوز با @ کارتون راه میفته؟
در سیشارپ، فقط یک راه برای نوشتن رشتهها وجود نداره. ابزارهای مختلفی در اختیار ماست که هر کدوم برای یه سناریوی خاص، بهترین انتخابه. تسلط بر این ابزارها، کد شما رو نه تنها خواناتر، که حرفهایتر هم میکنه.
1️⃣ روش کلاسیک: دردسرهای Escape Sequence (\)
این روش سنتیترین راهه. برای رشتههای ساده خوبه، ولی وقتی پای کاراکترهای خاص مثل بکاسلش (\) یا کوتیشن (") وسط بیاد، کد شما به سرعت زشت و ناخوانا میشه.
به خصوص برای مسیر فایلها در ویندوز، این روش یه کابوس واقعیه!
// هر \ باید دو بار نوشته بشه!
string classicPath = "C:\\Users\\MyUser\\Documents\\file.txt";
2️⃣ راه حل تمیز: Verbatim Literals (@)
اینجاست که @ مثل یه قهرمان وارد میشه! با گذاشتن یه @ قبل از رشته، شما به کامپایلر میگید: "هرچیزی که داخل این رشته هست رو دقیقاً همونطور که هست در نظر بگیر و هیچ کاراکتری رو escape نکن."
این قابلیت دو تا مزیت بزرگ داره:
مسیرهای خوانا:
// همون مسیر فایل، ولی تمیز و خوانا!
string verbatimPath = @"C:\Users\MyUser\Documents\file.txt";
متنهای چند خطی:
میتونید به راحتی و بدون نیاز به \n، متنهای چند خطی بنویسید.
string multiLine = @"این
یک متن
چند خطی است.";
نکته: برای استفاده از " داخل رشته @، کافیه دو بار بنویسیدش:
@"<tag id=""123"">"
3️⃣ قدرت مدرن: Raw String Literals ("""...""") (از C# 11 به بعد)
این جدیدترین و قدرتمندترین ابزار ماست که برای حل مشکلات کار با JSON، XML، HTML یا هر متن پیچیدهای طراحی شده.
رشته رو بین سه تا (یا بیشتر) دابل کوتیشن میذارید و دیگه هیچ نیازی به هیچگونه escape کردنی ندارید. حتی لازم نیست " رو دو بار بنویسید!
string json = """
{
"Name" : "C# Geeks",
"Quote" : "We write clean code!",
"Path" : "C:\Temp\Data.json"
}
""";
این قابلیت، کد شما رو به شکل چشمگیری تمیزتر و قابل نگهداریتر میکنه، به خصوص وقتی با متنهای ساختاریافته سر و کار دارید.
🤔 حرف حساب و ابزار شما
هر کدوم از این ابزارها، برای یه کاری ساخته شدن.
●برای رشتههای ساده ⟵ روش کلاسیک
●برای مسیر فایل و متنهای چند خطی ⟵ Verbatim (@)
●برای JSON، XML و متنهای پیچیده ⟵ Raw String (""")
شما از کدوم یکی از این روشها بیشتر استفاده میکنید؟ آیا از طرفدارای Raw String Literals جدید هستید یا هنوز با @ کارتون راه میفته؟
🔖 هشتگها :
#CSharp
#String
#CodingTips