--شناسهها(Identifiers):
نامهایی هستند که ما برنامهنویسها انتخاب میکنیم. مثلاً در کد بالا، System، x، Console و WriteLine همگی شناسه هستند.
-- قواعد مهم: به بزرگی و کوچکی حروف حساساند (case-sensitive).
--کنوانسیون نامگذاری:
برای پارامترها، متغیرهای محلی و فیلدهای خصوصی.
برای بقیه شناسهها (کلاسها، متدها، Propertyها).
--کلمات کلیدی(Keywords):
واژههایی هستند که برای کامپایلر معنی خاص و از پیش تعریف شدهای دارن. در مثال ما، using و int کلمات کلیدی هستند.
--کلمات کلیدی رزرو شده: بیشتر کلمات کلیدی #C رزرو شدهاند و نمیتوانید از آنها به عنوان شناسهی معمولی استفاده کنید. (مثل class, public, if, for و ...).
کلمات کلیدی متنی(Contextual Keywords):
یک سری کلمات کلیدی هستند که در برخی زمینهها معنی خاصی دارند ولی میتوانید از آنها به عنوان شناسه هم استفاده کنید، چون ابهامی ایجاد نمیکنند (مثل var, async, await, yield).
نامهایی هستند که ما برنامهنویسها انتخاب میکنیم. مثلاً در کد بالا، System، x، Console و WriteLine همگی شناسه هستند.
-- قواعد مهم: به بزرگی و کوچکی حروف حساساند (case-sensitive).
--کنوانسیون نامگذاری:
Camel Case (myLocalVariable)
برای پارامترها، متغیرهای محلی و فیلدهای خصوصی.
Pascal Case (MyLocakMethod)
برای بقیه شناسهها (کلاسها، متدها، Propertyها).
--کلمات کلیدی(Keywords):
واژههایی هستند که برای کامپایلر معنی خاص و از پیش تعریف شدهای دارن. در مثال ما، using و int کلمات کلیدی هستند.
--کلمات کلیدی رزرو شده: بیشتر کلمات کلیدی #C رزرو شدهاند و نمیتوانید از آنها به عنوان شناسهی معمولی استفاده کنید. (مثل class, public, if, for و ...).
نکته باحال : اگر واقعاً مجبور شدید، میتوانید با قرار دادن @ قبل از کلمه کلیدی، از آن به عنوان شناسه استفاده کنید:
int @using = 123;
کلمات کلیدی متنی(Contextual Keywords):
یک سری کلمات کلیدی هستند که در برخی زمینهها معنی خاصی دارند ولی میتوانید از آنها به عنوان شناسه هم استفاده کنید، چون ابهامی ایجاد نمیکنند (مثل var, async, await, yield).
--لیترالها(Literals):
دادههای خام و ثابتی که مستقیماً در کد وارد میکنیم. در مثال بالا، 12 و 30 لیترالهای عددی هستند.
--علامتهای نگارشی(Punctuators):
به ساختار و خوانایی کد کمک میکنند. بارزترین مثال، سمیکالن (;) است که یک دستور رو به پایان میرسونه.
--عملگرها (Operators):
عملیات خاصی روی مقادیر(Operands) انجام میدن. در کد مثال ما، این عملگرها رو داریم:
دادههای خام و ثابتی که مستقیماً در کد وارد میکنیم. در مثال بالا، 12 و 30 لیترالهای عددی هستند.
--علامتهای نگارشی(Punctuators):
به ساختار و خوانایی کد کمک میکنند. بارزترین مثال، سمیکالن (;) است که یک دستور رو به پایان میرسونه.
--عملگرها (Operators):
عملیات خاصی روی مقادیر(Operands) انجام میدن. در کد مثال ما، این عملگرها رو داریم:
= : عملگر انتساب (Assignment) که یک مقدار رو به یک متغیر اختصاص میده.
* : عملگر ضرب (Multiplication).
. : عملگر عضو (Member Access) برای دسترسی به اعضای یک کلاس یا شیء (مثل Console.WriteLine).
() : پرانتزها که برای فراخوانی متدها استفاده میشن. اگه متدی آرگومان نگیره، پرانتزها خالی میمونن.
🔖 هشتگها : #Syntax
📝 کامنتگذاری در #C:
سلام به گیکهای منظم و آیندهنگر!🧑💻
وقتی داریم کد مینویسیم، ممکنه یه جاهایی نیاز داشته باشیم توضیحاتی برای خودمون یا همتیمیهامون بذاریم. اینجاست که کامنتها (Comments) وارد عمل میشن! کامنتها خطوطی از کد هستن که کامپایلر #C اصلاً بهشون کاری نداره و فقط برای ما برنامهنویسها معنی دارن تا کد رو بهتر درک کنیم.
سی شارپ دو مدل کامنتگذاری اصلی و پرکاربرد داره که بهمون کمک میکنه کدمون همیشه خوانا و قابل فهم باشه:
سلام به گیکهای منظم و آیندهنگر!🧑💻
وقتی داریم کد مینویسیم، ممکنه یه جاهایی نیاز داشته باشیم توضیحاتی برای خودمون یا همتیمیهامون بذاریم. اینجاست که کامنتها (Comments) وارد عمل میشن! کامنتها خطوطی از کد هستن که کامپایلر #C اصلاً بهشون کاری نداره و فقط برای ما برنامهنویسها معنی دارن تا کد رو بهتر درک کنیم.
سی شارپ دو مدل کامنتگذاری اصلی و پرکاربرد داره که بهمون کمک میکنه کدمون همیشه خوانا و قابل فهم باشه:
1️⃣ کامنتهای تکخطی:
کاربرد: بهترین گزینه برای توضیح یک خط کد
خاص، یا ارائه یک نکته کوتاه و مختصر.
نحوه استفاده: با دو تا اسلش رو به جلو (//) شروع میشه و تا پایان همون خط ادامه پیدا میکنه.
مثال کاربردی:
این کامنتها برای وقتی که میخواید سریعاً یه توضیح کوچیک کنار کدتون بنویسید، فوقالعادهان!
(Single-Line Comments) //
کاربرد: بهترین گزینه برای توضیح یک خط کد
خاص، یا ارائه یک نکته کوتاه و مختصر.
نحوه استفاده: با دو تا اسلش رو به جلو (//) شروع میشه و تا پایان همون خط ادامه پیدا میکنه.
مثال کاربردی:
int counter = 0; // This is a Comment
این کامنتها برای وقتی که میخواید سریعاً یه توضیح کوچیک کنار کدتون بنویسید، فوقالعادهان!
2️⃣ کامنتهای چندخطی:
کاربرد: ایدهآل برای توضیحات طولانیتر، شرح دادن یک بلوک کد بزرگ، یا حتی غیرفعال کردن موقتی چند خط کد.
نحوه استفاده: با /* شروع میشه و با */ به پایان میرسه و میتونه شامل چندین خط باشه.
مثال کاربردیتر:
این کامنتها زمانی به کار میان که نیاز به توضیح عمیقتر یا خلاصهای از عملکرد یک بخش بزرگتر از کد دارید.
(Multiline Comments) /* ... */
کاربرد: ایدهآل برای توضیحات طولانیتر، شرح دادن یک بلوک کد بزرگ، یا حتی غیرفعال کردن موقتی چند خط کد.
نحوه استفاده: با /* شروع میشه و با */ به پایان میرسه و میتونه شامل چندین خط باشه.
مثال کاربردیتر:
/*
این بخش از کد مسئول محاسبه
مجموع اعداد ۱ تا ۱۰ است.
از یک حلقه for برای این کار استفاده شده.
*/
int sum = 0;
for (int i = 1; i <= 10; i++)
{
sum += i;
}
این کامنتها زمانی به کار میان که نیاز به توضیح عمیقتر یا خلاصهای از عملکرد یک بخش بزرگتر از کد دارید.
💡نکته حرفهای:
کامنتگذاری هوشمندانه، نه تنها کد شما رو برای بقیه (و خودتون در آینده!) مثل روز روشن میکنه، بلکه یک مستندسازی داخلی ارزشمند برای پروژههای بزرگ محسوب میشه. سعی کنید کامنتها رو همیشه بهروز نگه دارید و از کامنتهای تکراری و بیفایده پرهیز کنید.
کامنتگذاری هوشمندانه، نه تنها کد شما رو برای بقیه (و خودتون در آینده!) مثل روز روشن میکنه، بلکه یک مستندسازی داخلی ارزشمند برای پروژههای بزرگ محسوب میشه. سعی کنید کامنتها رو همیشه بهروز نگه دارید و از کامنتهای تکراری و بیفایده پرهیز کنید.
🔖 هشتگها : #Comments
💎 فوت و فن انواع داده (Types) در #C :
از صفر تا کلاسهای سفارشی
هر برنامهنویس کاردرستی میدونه که برای نوشتن کدهای قدرتمند و تمیز، اول باید به مفهوم «انواع داده» (Types) مسلط شد. این مفهوم، مثل DNA برای دادههای ما عمل میکنه.
فکر کنید هر Type، شناسنامهی یه مقداره. این شناسنامه به #C میگه که این داده دقیقاً چیه، چه چیزایی تو خودش نگه میداره و چه کارایی از دستش برمیاد.
مثلاً، متغیر (Variable) رو داریم که مثل یه گاوصندوقه؛ هر لحظه میتونیم یه مقدار جدید توش بذاریم. در مقابل، ثابت (Constant) مثل یه سنگنوشتهست؛ یه بار که تعریف شد، تا ابد همون باقی میمونه!
نکته طلایی: 💡 در #C، هیچ مقداری بیهویت نیست. هر مقدار یک Type دارد که شخصیت و رفتارش را شکل میدهد.
از صفر تا کلاسهای سفارشی
هر برنامهنویس کاردرستی میدونه که برای نوشتن کدهای قدرتمند و تمیز، اول باید به مفهوم «انواع داده» (Types) مسلط شد. این مفهوم، مثل DNA برای دادههای ما عمل میکنه.
فکر کنید هر Type، شناسنامهی یه مقداره. این شناسنامه به #C میگه که این داده دقیقاً چیه، چه چیزایی تو خودش نگه میداره و چه کارایی از دستش برمیاد.
مثلاً، متغیر (Variable) رو داریم که مثل یه گاوصندوقه؛ هر لحظه میتونیم یه مقدار جدید توش بذاریم. در مقابل، ثابت (Constant) مثل یه سنگنوشتهست؛ یه بار که تعریف شد، تا ابد همون باقی میمونه!
// 'x' یه متغیر از نوع int است.
int x = 12 * 30;
Console.WriteLine(x); // 360
// 'y' یک ثابت است که مقدارش غیرقابل تغییره.
const int y = 360;
نکته طلایی: 💡 در #C، هیچ مقداری بیهویت نیست. هر مقدار یک Type دارد که شخصیت و رفتارش را شکل میدهد.
🧰 ابزارهای آماده در جعبهابزار #C :
سیشارپ یه سری Type آماده و پرکاربرد رو از اول در اختیارمون گذاشته که آچار فرانسهی ما هستن. این سه تا از مهمترینهاشونن:
نماینده اعداد صحیح. هرجا به محاسبات، شمارندهها یا هر نوع عملیات ریاضی نیاز دارید، int اولین و بهترین انتخاب شماست.
برای نمایش و دستکاری هر نوع داده متنی، از نام کاربری گرفته تا یک پیام طولانی. قدرت واقعی string در متدهای بینظیرشه.
این نوع فقط دو حالت میشناسه: true یا false. تمام تصمیمهای پیچیده برنامه، از بررسی اجازه دسترسی گرفته تا فعال یا غیرفعال کردن یک ویژگی، زیر سر همین bool هست.
سیشارپ یه سری Type آماده و پرکاربرد رو از اول در اختیارمون گذاشته که آچار فرانسهی ما هستن. این سه تا از مهمترینهاشونن:
int: سلطان اعداد
نماینده اعداد صحیح. هرجا به محاسبات، شمارندهها یا هر نوع عملیات ریاضی نیاز دارید، int اولین و بهترین انتخاب شماست.
int soldItems = 99;
int stock = 1000 - soldItems;
string: استاد کار با متن
برای نمایش و دستکاری هر نوع داده متنی، از نام کاربری گرفته تا یک پیام طولانی. قدرت واقعی string در متدهای بینظیرشه.
string rawEmail = " TestUser@example.com ";
// فضای خالی رو حذف و همه رو به حروف کوچک تبدیل میکنه
string cleanEmail = rawEmail.Trim().ToLower();
Console.WriteLine(cleanEmail); // testuser@example.com
bool: فرماندهی منطق برنامه
این نوع فقط دو حالت میشناسه: true یا false. تمام تصمیمهای پیچیده برنامه، از بررسی اجازه دسترسی گرفته تا فعال یا غیرفعال کردن یک ویژگی، زیر سر همین bool هست.
bool hasPermission = true;
if (hasPermission)
{
Console.WriteLine("Access Granted");
}
🏗 اینجا قضیه جدی میشه: ساختن Typeهای شخصی!
قدرت واقعی شما به عنوان یه توسعهدهنده، زمانی شکوفا میشه که دیگه فقط از ابزارهای آماده استفاده نمیکنید، بلکه با استفاده از class، ابزارهای تخصصی خودتون رو میسازید. اینجا شما خالق هستید.
مثلاً، فرض کنید یه مبدل واحد نیاز داریم. به جای اینکه فرمول تبدیل رو همه جای کد پخش کنیم، یک بار برای همیشه یه class براش میسازیم.
ببینید چقدر تمیز و حرفهای ازش استفاده میکنیم:
و اینم نقشهی ساخت اون ابزار قدرتمند:
قدرت واقعی شما به عنوان یه توسعهدهنده، زمانی شکوفا میشه که دیگه فقط از ابزارهای آماده استفاده نمیکنید، بلکه با استفاده از class، ابزارهای تخصصی خودتون رو میسازید. اینجا شما خالق هستید.
مثلاً، فرض کنید یه مبدل واحد نیاز داریم. به جای اینکه فرمول تبدیل رو همه جای کد پخش کنیم، یک بار برای همیشه یه class براش میسازیم.
ببینید چقدر تمیز و حرفهای ازش استفاده میکنیم:
var feetToInchesConverter = new UnitConverter(12);
var milesToFeetConverter = new UnitConverter(5280);
int lengthInInches = feetToInchesConverter.Convert(30);
Console.WriteLine($"30 feet is {lengthInInches} inches."); // 30 feet is 360 inches.
و اینم نقشهی ساخت اون ابزار قدرتمند:
public class UnitConverter
{
// فیلد داخلی برای نگهداری منطق
private readonly int ratio;
// با این تابع، بهش میگیم با چه فرمولی کار کنه
public UnitConverter(int unitRatio)
{
this.ratio = unitRatio;
}
// و اینم خودِ عملیات تبدیل که انجام میده
public int Convert(int unit)
{
return unit * this.ratio;
}
}
🥊 دوئل حافظه در #C :
تا حالا شده یه متغیر رو جایی عوض کنی و ببینی یه جای دیگه هم ناخواسته تغییر کرده؟ یا برعکس، انتظار داشتی تغییر کنه ولی نکرده؟ ریشه ۹۰٪ این مشکلات، درک نکردن تفاوت بین Value Type و Reference Type هست.
این بحث فقط یه تئوری خشک و خالی نیست، بلکه کلید نوشتن کدهای بدون باگ و قابل پیشبینیه. بزن بریم این راز بزرگ رو کشف کنیم!
فکر کنید Value Type مثل یه تیکه کاغذه. وقتی اون رو به متغیر دیگهای میدین، یه کپی کامل ازش گرفته میشه. حالا هر بلایی سر اون کپی بیاد، کاغذ اصلی شما صحیح و سالمه!
شامل چه چیزایی میشه؟ تمام انواع عددی (int, double و...)، bool، char و مهمتر از همه، structها.
بیاین با مثال Point که به صورت struct تعریف شده ببینیم:
همونطور که میبینید، p2 زندگی خودشو داره و از تغییر p1 خبردار هم نمیشه!
حالا فکر کنید Reference Type مثل کلید یه خونهست. شما خودِ خونه رو به کسی نمیدین، فقط یه کلید ازش کپی میکنید و بهش میدین. هر کسی که کلید رو داشته باشه، میتونه بره داخل و دکوراسیون رو عوض کنه و این تغییر برای همه اونایی که کلید دارن، قابل مشاهدهست!
شامل چه چیزایی میشه؟ تمام classها، string، آرایهها، delegateها و interfaceها.
حالا همون مثال Point رو این بار به صورت class تعریف میکنیم:
اینجا دیگه p1 و p2 شریک جرم هستن! تغییر روی یکی، روی اون یکی هم تأثیر میذاره.
Value Types در برابر Reference Types
تا حالا شده یه متغیر رو جایی عوض کنی و ببینی یه جای دیگه هم ناخواسته تغییر کرده؟ یا برعکس، انتظار داشتی تغییر کنه ولی نکرده؟ ریشه ۹۰٪ این مشکلات، درک نکردن تفاوت بین Value Type و Reference Type هست.
این بحث فقط یه تئوری خشک و خالی نیست، بلکه کلید نوشتن کدهای بدون باگ و قابل پیشبینیه. بزن بریم این راز بزرگ رو کشف کنیم!
Value Types: کپی برابر اصل
فکر کنید Value Type مثل یه تیکه کاغذه. وقتی اون رو به متغیر دیگهای میدین، یه کپی کامل ازش گرفته میشه. حالا هر بلایی سر اون کپی بیاد، کاغذ اصلی شما صحیح و سالمه!
شامل چه چیزایی میشه؟ تمام انواع عددی (int, double و...)، bool، char و مهمتر از همه، structها.
بیاین با مثال Point که به صورت struct تعریف شده ببینیم:
public struct Point { public int X, Y; }
Point p1 = new Point();
p1.X = 7;
// این خط، یک کپی کامل از p1 در p2 ایجاد میکنه
Point p2 = p1;
// حالا p1 و p2 دو موجودیت کاملاً جدا در حافظه هستن
Console.WriteLine($"p1.X: {p1.X}, p2.X: {p2.X}");
// p1.X: 7
// p2.X: 7
// اگه p1 رو تغییر بدیم، هیچ تأثیری روی p2 نداره
p1.X = 9;
Console.WriteLine($"p1.X: {p1.X}, p2.X: {p2.X}");
// p1.X: 9
// p2.X: 7همونطور که میبینید، p2 زندگی خودشو داره و از تغییر p1 خبردار هم نمیشه!
Reference Types: یک آدرس، چند نفر
حالا فکر کنید Reference Type مثل کلید یه خونهست. شما خودِ خونه رو به کسی نمیدین، فقط یه کلید ازش کپی میکنید و بهش میدین. هر کسی که کلید رو داشته باشه، میتونه بره داخل و دکوراسیون رو عوض کنه و این تغییر برای همه اونایی که کلید دارن، قابل مشاهدهست!
شامل چه چیزایی میشه؟ تمام classها، string، آرایهها، delegateها و interfaceها.
حالا همون مثال Point رو این بار به صورت class تعریف میکنیم:
public class Point { public int X, Y; }
// ...
Point p1 = new Point();
p1.X = 7;
// این خط، فقط آدرس (رفرنس) p1 رو در p2 کپی میکنه
// حالا هر دو به یک آبجکت در حافظه اشاره دارن
Point p2 = p1;
Console.WriteLine($"p1.X: {p1.X}, p2.X: {p2.X}");
// p1.X: 7
// p2.X: 7
// اگه p1 رو تغییر بدیم، چون p2 هم به همون خونه نگاه میکنه، اونم تغییر رو میبینه
p1.X = 9;
Console.WriteLine($"p1.X: {p1.X}, p2.X: {p2.X}");
// p1.X: 9,
// p2.X: 9اینجا دیگه p1 و p2 شریک جرم هستن! تغییر روی یکی، روی اون یکی هم تأثیر میذاره.
🔖 هشتگها : #MemoryManagement
⚠️ خطرناکترین کلمه در #C :
اگه یه جایزهای برای منفورترین و رایجترین خطا تو دنیای داتنت وجود داشت، بدون شک به NullReferenceException میرسید. این خطا مثل یه روح سرگردانه که هر لحظه ممکنه ظاهر بشه و برنامهتون رو از کار بندازه. اما ریشه این کابوس، فقط یه کلمهست: null.
بزن بریم بفهمیم این null چیه و چطور از فاجعه جلوگیری کنیم.
👻 null دقیقاً یعنی چی؟
فکر کنید یه متغیر از نوع Reference Type (مثل یه class)، یه کارت ویزیته که روش آدرس یه خونه نوشته شده.
"null"
یعنی اون کارت ویزیت کاملاً سفیده و هیچ آدرسی روش نیست. پوچه! این رفرنس به هیچ آبجکتی در حافظه اشاره نمیکنه.
💥 فاجعه کجا رخ میده؟ (NullReferenceException)
حالا اگه شما سعی کنید با اون کارت ویزیت سفید، درِ خونه رو باز کنید (یعنی به یکی از اعضای اون آبجکت مثل X دسترسی پیدا کنید)، برنامه قاطی میکنه و با تمام قدرت فریاد میزنه: NullReferenceException!
ترجمه این خطا به زبون خودمونی اینه: "داری سعی میکنی از چیزی استفاده کنی که اصلاً وجود نداره!"
🚫 تکلیف Value Type ها چیه؟
خبر خوب اینه که Value Type ها (مثل int, struct, bool) ذاتاً نمیتونن null باشن. اونا همیشه یه مقداری دارن (حتی اگه مقدار پیشفرضشون صفر باشه).
Value Type مثل یه سکه هست که یا این روئه یا اون رو؛ حالت "هیچی" نداره.
🤔 حرف حساب و تکنیک شما چیه؟
مقابله با null یه مهارت روزمرهست. از چک کردنهای ساده مثل if (myVar != null) گرفته تا تکنیکهای مدرنتر در C#.
استراتژی شما برای جلوگیری از این خطای رو مخ چیه؟ آیا از Null-conditional operator (?.) و Null-coalescing operator (??) زیاد استفاده میکنید؟ یا روش خاصی برای مدیریت null تو کدهاتون دارید؟
همه چیز درباره null
اگه یه جایزهای برای منفورترین و رایجترین خطا تو دنیای داتنت وجود داشت، بدون شک به NullReferenceException میرسید. این خطا مثل یه روح سرگردانه که هر لحظه ممکنه ظاهر بشه و برنامهتون رو از کار بندازه. اما ریشه این کابوس، فقط یه کلمهست: null.
بزن بریم بفهمیم این null چیه و چطور از فاجعه جلوگیری کنیم.
👻 null دقیقاً یعنی چی؟
فکر کنید یه متغیر از نوع Reference Type (مثل یه class)، یه کارت ویزیته که روش آدرس یه خونه نوشته شده.
"null"
یعنی اون کارت ویزیت کاملاً سفیده و هیچ آدرسی روش نیست. پوچه! این رفرنس به هیچ آبجکتی در حافظه اشاره نمیکنه.
class Point { public int X, Y; }
// اینجا یه رفرنس به اسم p داریم که به هیچجا اشاره نمیکنه
Point p = null;
Console.WriteLine(p == null);
// True💥 فاجعه کجا رخ میده؟ (NullReferenceException)
حالا اگه شما سعی کنید با اون کارت ویزیت سفید، درِ خونه رو باز کنید (یعنی به یکی از اعضای اون آبجکت مثل X دسترسی پیدا کنید)، برنامه قاطی میکنه و با تمام قدرت فریاد میزنه: NullReferenceException!
ترجمه این خطا به زبون خودمونی اینه: "داری سعی میکنی از چیزی استفاده کنی که اصلاً وجود نداره!"
// این خط فاجعه رو به بار میاره!
// چون p به هیچ آبجکتی اشاره نمیکنه، X هم وجود نداره
Console.WriteLine(p.X);
🚫 تکلیف Value Type ها چیه؟
خبر خوب اینه که Value Type ها (مثل int, struct, bool) ذاتاً نمیتونن null باشن. اونا همیشه یه مقداری دارن (حتی اگه مقدار پیشفرضشون صفر باشه).
Value Type مثل یه سکه هست که یا این روئه یا اون رو؛ حالت "هیچی" نداره.
struct Point { public int X, Y; }
// این کدها اصلاً کامپایل نمیشن! چون Value Type نمیتونه null باشه
Point p = null; // Compile-time error
int x = null; // Compile-time errorنکته: البته C# برای شرایط خاص، چیزی به اسم "Nullable Value Types" داره (مثلاً int?) که بعداً بهش میرسیم. ولی اصل داستان همینه.
🤔 حرف حساب و تکنیک شما چیه؟
مقابله با null یه مهارت روزمرهست. از چک کردنهای ساده مثل if (myVar != null) گرفته تا تکنیکهای مدرنتر در C#.
استراتژی شما برای جلوگیری از این خطای رو مخ چیه؟ آیا از Null-conditional operator (?.) و Null-coalescing operator (??) زیاد استفاده میکنید؟ یا روش خاصی برای مدیریت null تو کدهاتون دارید؟
🔖 هشتگها :
#CSharp
#ErrorHandling #NullReferenceException
خانواده بزرگ اعداد در #C :
وقتی تو #C میخوایم با اعداد کار کنیم، فقط int رو نداریم! یه خانواده بزرگ و متنوع از انواع عددی وجود داره که هر کدوم برای یه کار خاص ساخته شدن و قدرتهای متفاوتی دارن.
بیاید با همه اعضای اصلی این خانواده آشنا بشیم تا بدونید برای هر موقعیتی، کدوم سرباز رو باید به میدان بفرستید.
اینها برای کار با اعداد کامل و بدون اعشار هستن.
انتخاب اول و پیشفرض برای ۹۰٪ کارها. برای شمارندهها، شناسهها (ID) و محاسبات عمومی، همیشه انتخاب اول شما int هست.
وقتی int برای جا دادن عددتون کم میاره، long مثل یه تانک وارد میشه و مشکل رو حل میکنه.
اینا نسخههای کوچیکتر int هستن. معمولاً بهشون نیاز پیدا نمیکنید، مگر اینکه روی حافظه خیلی حساس باشید.
اینا همون اعداد صحیح هستن، با این تفاوت که فقط مقادیر مثبت رو قبول میکنن (Unsigned). در عوض، میتونن اعداد مثبت بزرگتری رو نسبت به همتای علامتدار خودشون ذخیره کنن.
اینها برای کار با اعداد اعشاری و کسری به کار میان.
انتخاب پیشفرض و سریع برای اعداد اعشاریه. برای محاسبات علمی، گرافیکی و فیزیکی که سرعت در اونها مهمه، double بهترین گزینهست.
این یکی فوقالعاده دقیقه و هیچ خطای گردکردنی نداره. برای هر نوع محاسبه مالی و پولی، استفاده از هر چیزی به جز decimal یه اشتباه بزرگه!
مثل یه نسخه کوچیکتر و کمدقتتر از double میمونه. جایی کاربرد داره که هم به اعشار نیاز دارید و هم حافظه براتون خیلی مهمه.
وقتی تو #C میخوایم با اعداد کار کنیم، فقط int رو نداریم! یه خانواده بزرگ و متنوع از انواع عددی وجود داره که هر کدوم برای یه کار خاص ساخته شدن و قدرتهای متفاوتی دارن.
بیاید با همه اعضای اصلی این خانواده آشنا بشیم تا بدونید برای هر موقعیتی، کدوم سرباز رو باید به میدان بفرستید.
اعداد صحیح (Integers):
اینها برای کار با اعداد کامل و بدون اعشار هستن.
int
انتخاب اول و پیشفرض برای ۹۰٪ کارها. برای شمارندهها، شناسهها (ID) و محاسبات عمومی، همیشه انتخاب اول شما int هست.
long
وقتی int برای جا دادن عددتون کم میاره، long مثل یه تانک وارد میشه و مشکل رو حل میکنه.
short و sbyte
اینا نسخههای کوچیکتر int هستن. معمولاً بهشون نیاز پیدا نمیکنید، مگر اینکه روی حافظه خیلی حساس باشید.
uint, ulong, ushort, byte
اینا همون اعداد صحیح هستن، با این تفاوت که فقط مقادیر مثبت رو قبول میکنن (Unsigned). در عوض، میتونن اعداد مثبت بزرگتری رو نسبت به همتای علامتدار خودشون ذخیره کنن.
Real Numbers
اینها برای کار با اعداد اعشاری و کسری به کار میان.
double
انتخاب پیشفرض و سریع برای اعداد اعشاریه. برای محاسبات علمی، گرافیکی و فیزیکی که سرعت در اونها مهمه، double بهترین گزینهست.
decimal
این یکی فوقالعاده دقیقه و هیچ خطای گردکردنی نداره. برای هر نوع محاسبه مالی و پولی، استفاده از هر چیزی به جز decimal یه اشتباه بزرگه!
float
مثل یه نسخه کوچیکتر و کمدقتتر از double میمونه. جایی کاربرد داره که هم به اعشار نیاز دارید و هم حافظه براتون خیلی مهمه.
🪄 جادوی اعداد در #C :
نوشتن اعداد مثل یک حرفهای (Literals, Suffixes & More)
فکر میکنی نوشتن 1000 تو سیشارپ همیشه به معنی int هست؟ یا چطور به کامپایلر بفهمونیم منظورمون یه عدد decimalئه نه double؟
اینا جزئیات و "فوت کوزهگری" هستن که فرق کدنویس معمولی و حرفهای رو مشخص میکنه. بزن بریم این ترفندها رو یاد بگیریم!
👓 خوانایی کد با لیترالهای حرفهای
نوشتن اعداد، فقط مقدارشون نیست؛ خوانایی هم مهمه!
جداکننده ارقام (_): برای اعداد بزرگ، میتونید از آندرلاین برای جدا کردن ارقام و خوانایی بیشتر استفاده کنید. کامپایلر این آندرلاینها رو نادیده میگیره.
مبنای شانزده (Hexadecimal): با پیشوند 0x، میتونید اعداد رو در مبنای ۱۶ بنویسید. این برای کار با رنگها، فلگها و عملیات سطح پایین خیلی کاربردیه.
مبنای دو (Binary): با پیشوند 0b، میتونید مستقیماً عدد رو به صورت باینری وارد کنید.
🏷 پسوندها (Suffixes): تعیین تکلیف برای کامپایلر!
بعضی وقتا کامپایلر خودش نوع عدد رو حدس میزنه (که بهش میگیم Type Inference)، ولی گاهی ما باید حرف آخر رو بزنیم! اینجاست که پسوندها وارد میشن.
مهمترینهاشون اینان:
اگه این پسوند رو نذارید، کامپایلر عدد اعشاری شما رو double در نظر میگیره و کدتون خطا میده چون double به راحتی به float تبدیل نمیشه.
این یکی فوقالعاده مهمه. برای تمام محاسبات مالی و پولی، باید از decimal استفاده کنید و برای مقداردهی بهش، حتماً از پسوند M استفاده کنید.
این پسوندها کمتر ضروری هستن، چون معمولاً کامپایلر میتونه نوعشون رو حدس بزنه یا به صورت خودکار تبدیل کنه. ولی خوبه که بدونید وجود دارن.
❓ شما چطور اعداد رو مینویسید؟
اینا فقط یه سری قاعده خشک و خالی نیستن، ابزارهایی برای نوشتن کد دقیقتر و خواناتر هستن.
نوشتن اعداد مثل یک حرفهای (Literals, Suffixes & More)
فکر میکنی نوشتن 1000 تو سیشارپ همیشه به معنی int هست؟ یا چطور به کامپایلر بفهمونیم منظورمون یه عدد decimalئه نه double؟
اینا جزئیات و "فوت کوزهگری" هستن که فرق کدنویس معمولی و حرفهای رو مشخص میکنه. بزن بریم این ترفندها رو یاد بگیریم!
👓 خوانایی کد با لیترالهای حرفهای
نوشتن اعداد، فقط مقدارشون نیست؛ خوانایی هم مهمه!
جداکننده ارقام (_): برای اعداد بزرگ، میتونید از آندرلاین برای جدا کردن ارقام و خوانایی بیشتر استفاده کنید. کامپایلر این آندرلاینها رو نادیده میگیره.
int bigNumber = 1_000_000; // خیلی خواناتر از 1000000
var binaryData = 0b1010_1011_1100;
مبنای شانزده (Hexadecimal): با پیشوند 0x، میتونید اعداد رو در مبنای ۱۶ بنویسید. این برای کار با رنگها، فلگها و عملیات سطح پایین خیلی کاربردیه.
int redColor = 0xFF0000;
مبنای دو (Binary): با پیشوند 0b، میتونید مستقیماً عدد رو به صورت باینری وارد کنید.
var filePermissions = 0b110_110_100; // rwx-wx--
🏷 پسوندها (Suffixes): تعیین تکلیف برای کامپایلر!
بعضی وقتا کامپایلر خودش نوع عدد رو حدس میزنه (که بهش میگیم Type Inference)، ولی گاهی ما باید حرف آخر رو بزنیم! اینجاست که پسوندها وارد میشن.
مهمترینهاشون اینان:
F برای float
اگه این پسوند رو نذارید، کامپایلر عدد اعشاری شما رو double در نظر میگیره و کدتون خطا میده چون double به راحتی به float تبدیل نمیشه.
// float f = 4.5; // ❌ کامپایل نمیشه!
float f = 4.5F; // ✅ درسته!
M برای decimal
این یکی فوقالعاده مهمه. برای تمام محاسبات مالی و پولی، باید از decimal استفاده کنید و برای مقداردهی بهش، حتماً از پسوند M استفاده کنید.
// decimal balance = 100.99; // ❌ کامپایل نمیشه!
decimal balance = 100.99M; // ✅ درسته!
L برای long و U برای unsigned
این پسوندها کمتر ضروری هستن، چون معمولاً کامپایلر میتونه نوعشون رو حدس بزنه یا به صورت خودکار تبدیل کنه. ولی خوبه که بدونید وجود دارن.
long bigNum = 9_000_000_000L; // با L بهش میگیم این یه عدد خیلی بزرگه
❓ شما چطور اعداد رو مینویسید؟
اینا فقط یه سری قاعده خشک و خالی نیستن، ابزارهایی برای نوشتن کد دقیقتر و خواناتر هستن.
🔖 هشتگها :
#CSharp
#CodingTips
#Literals
🎲 قوانین بازی با اعداد در #C :
تا حالا فکر کردید وقتی یه int رو توی یه long میریزید، یا یه double رو به زور تو یه int جا میدید، پشت صحنه چه اتفاقی میفته؟
این تبدیلها (Conversions) قوانین خودشون رو دارن و ندونستن این قوانین، میتونه به از دست رفتن داده و باگهای وحشتناک ختم بشه. بزن بریم این قوانین رو یک بار برای همیشه یاد بگیریم.
این تبدیلها مثل ریختن آب از یه لیوان کوچیک تو یه سطل بزرگه؛ کاملاً امن، بدون دردسر و بدون از دست رفتن حتی یک قطره آب!
وقتی نوع داده مقصد، گنجایش تمام مقادیر ممکن در نوع داده مبدأ رو داشته باشه، #C خودش هوشمندانه و به صورت خودکار این تبدیل رو انجام میده.
اینجا دیگه سیشارپ به شما اجازه نمیده این کار رو خودکار انجام بدید. شما باید با مسئولیت خودتون و با استفاده از Casting (قرار دادن نوع مقصد داخل پرانتز)، به کامپایلر بگید: "میدونم دارم چیکار میکنم و ریسکش رو میپذیرم!"
💣 دو تله مرگبار در تبدیلهای صریح
وقتی کست میکنید، حواستون به این دوتا تله باشه:
بریده شدن اعشار (Truncation):
وقتی یه عدد اعشاری (double یا float) رو به یه عدد صحیح (int) کست میکنید، بخش اعشاری عدد گرد نمیشه، بلکه وحشیانه بریده و حذف میشه!
از دست رفتن دقت (Precision Loss):
گاهی اوقات، حتی در تبدیلهای امن (مثل int به float)، ممکنه دقت رو از دست بدید. float میتونه اعداد خیلی بزرگتری رو نشون بده، ولی دقتش در جزئیات کمتر از int هست.
همه چیز درباره تبدیلهای عددی (Casting)
تا حالا فکر کردید وقتی یه int رو توی یه long میریزید، یا یه double رو به زور تو یه int جا میدید، پشت صحنه چه اتفاقی میفته؟
این تبدیلها (Conversions) قوانین خودشون رو دارن و ندونستن این قوانین، میتونه به از دست رفتن داده و باگهای وحشتناک ختم بشه. بزن بریم این قوانین رو یک بار برای همیشه یاد بگیریم.
✅ نوع اول: تبدیلهای امن و ضمنی (Implicit)
این تبدیلها مثل ریختن آب از یه لیوان کوچیک تو یه سطل بزرگه؛ کاملاً امن، بدون دردسر و بدون از دست رفتن حتی یک قطره آب!
وقتی نوع داده مقصد، گنجایش تمام مقادیر ممکن در نوع داده مبدأ رو داشته باشه، #C خودش هوشمندانه و به صورت خودکار این تبدیل رو انجام میده.
int myInt = 12345;
// int (32-bit) به راحتی در long (64-bit) جا میشه
long myLong = myInt;
// int (عدد صحیح) به راحتی به double (عدد اعشاری) تبدیل میشه
double myDouble = myInt;
float myFloat = 123.45F;
// float (32-bit) به راحتی در double (64-bit) جا میشه
double anotherDouble = myFloat;
⚠️ نوع دوم: تبدیلهای خطرناک و صریح (Explicit Casting)حالا برعکسش رو تصور کنید: میخواید آب یه سطل بزرگ رو تو یه لیوان کوچیک جا بدید. احتمال اینکه آب سرریز بشه و بخشی ازش از دست بره، خیلی زیاده!
اینجا دیگه سیشارپ به شما اجازه نمیده این کار رو خودکار انجام بدید. شما باید با مسئولیت خودتون و با استفاده از Casting (قرار دادن نوع مقصد داخل پرانتز)، به کامپایلر بگید: "میدونم دارم چیکار میکنم و ریسکش رو میپذیرم!"
long bigNum = 3_000_000_000L;
double myDouble = 12345.6789;
// برای جا دادن long در int، باید کست کنیم
// اگه عدد بزرگ باشه، داده از دست میره!
int myInt = (int)bigNum;
// برای جا دادن double در int، باید کست کنیم
int anotherInt = (int)myDouble; // مقدارش میشه 12345
💣 دو تله مرگبار در تبدیلهای صریح
وقتی کست میکنید، حواستون به این دوتا تله باشه:
بریده شدن اعشار (Truncation):
وقتی یه عدد اعشاری (double یا float) رو به یه عدد صحیح (int) کست میکنید، بخش اعشاری عدد گرد نمیشه، بلکه وحشیانه بریده و حذف میشه!
double price = 99.99;
int priceAsInt = (int)price; // مقدارش میشه 99، نه 100!
از دست رفتن دقت (Precision Loss):
گاهی اوقات، حتی در تبدیلهای امن (مثل int به float)، ممکنه دقت رو از دست بدید. float میتونه اعداد خیلی بزرگتری رو نشون بده، ولی دقتش در جزئیات کمتر از int هست.
int bigInt = 100_000_001;
// اینجا مقدار حفظ میشه، ولی دقت از بین میره
float myFloat = bigInt;
// وقتی برمیگردونیم، میبینیم که عدد تغییر کرده!
int convertedInt = (int)myFloat; // مقدارش میشه 100_000_000
🔖 هشتگها :
#CSharp
#CodingTips
#Casting
💡 نکته سریع #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