همان نقشهای که دنبالش بودی، اینجاست.
از پست اینستاگرام آمدهای؟ اینجا مبانی C# را با پروژه ثبت هزینه تمرین میکنی؛ همراه تمرین و معیار سنجش هر مرحله. مقاله و فایل رایگاناند؛ بدون ثبتنام یا شماره موبایل.
- برای چه کسی؟
- مبتدی و شروع از صفر
- پیشنیاز
- کار معمول با کامپیوتر
- زمان پیشنهادی
- روزانه ۶۰ تا ۹۰ دقیقه
- خروجی مسیر
- برنامه ثبت هزینه با C#
معیار پیشرفت، تمامکردن ویدیوها نیست؛ حل یک تمرین تازه بدون کپیکردن پاسخ است. ۳۰ روز، چارچوب تمرین است؛ نه وعده استخدام یا حرفهایشدن.

برای شروع برنامهنویسی، اول چه چیزی را انتخاب کنیم؟
شروع گاهی از زیادی انتخابها سخت میشود: امروز پایتون، فردا طراحی سایت و هفته بعد یک فریمورک تازه. در این نقشه راه یادگیری برنامهنویسی، روی یک زبان، یک پروژه کوچک و یک معیار روشن تمرکز میکنیم: تبدیل مسئله به دستورهای قابل اجرا.
زبان این مسیر C#، یا سیشارپ، است. برنامه کنسولی، ورودی و خروجی متنی دارد؛ پس فعلاً درگیر ظاهر صفحه، دیتابیس و حساب کاربری نمیشوی. همین پایهها بعداً در ASP.NET Core کاربرد دارند.
هر جلسه: ۱۵ دقیقه یادگیری، ۴۰ تا ۶۰ دقیقه کدنویسی و ۱۰ دقیقه بررسی خروجی. با وقت کمتر، هر روز برنامه را در دو جلسه انجام بده؛ کیفیت تمرین مهمتر از سرعت است.
آمادهسازی محیط C# روی ویندوز
برای ساخت برنامه، SDK لازم داری؛ Runtime فقط برای اجرای برنامههای ساختهشده کافی است و ابزار ساخت پروژه را کامل در اختیارت نمیگذارد. از صفحه رسمی دانلود .NET 10، نسخه SDK متناسب با معماری ویندوزت را نصب کن؛ برای بیشتر لپتاپهای معمول ویندوزی گزینه x64 مناسب است، اما دستگاه ARM نسخه خودش را لازم دارد. آخرین بهروزرسانی همان شاخه را بگیر. طبق سیاست رسمی پشتیبانی .NET، نسخه ۱۰ از نوع LTS است.
برای ویرایش، Visual Studio Code و افزونه رسمی C# Dev Kit کافی است. پس از نصب SDK، ترمینال را دوباره باز کن و در پوشه تمرین این فرمانها را اجرا کن:
dotnet --version
dotnet new console -n GoljaamExpenseTracker
cd GoljaamExpenseTracker
dotnet runفرمانها بهترتیب نسخه SDK، ساخت پروژه، ورود به پوشه و اجرا هستند. اگر dotnet شناخته نشد، نصب SDK را بررسی کن. برای خطای «پروژه پیدا نشد»، مطمئن شو فایل GoljaamExpenseTracker.csproj در پوشه جاری است.
دستور چاپ را در Program.cs تغییر بده. قالب جدید با دستورهای سطح بالا کار میکند؛ نوشتن دستی Main لازم نیست. مرجع نصب: آموزش رسمی برنامه کنسولی.
Console.WriteLine("Hello, Goljaam!");نقشه راه عملی: یک پروژه، چهار مرحله رشد
پروژه ما «ثبت هزینههای روزانه» است؛ نه نرمافزار بانکی یا حسابداری واقعی. ابتدا یک هزینه را گزارش میکند، بعد چند هزینه را جمع میزند، سپس کدش به توابع کوچک تقسیم میشود و در پایان دادهها را در فایل نگه میدارد. هر بار فقط یک نوع پیچیدگی اضافه میکنیم.
- ۱. یک هزینهمتغیر، ورودی، شرط
- ۲. چند هزینهحلقه و مجموعه
- ۳. کد قابل فهمتابع و مدل Expense
- ۴. ماندگاریذخیره و بازیابی JSON
قبل از تایپ: ورودی، پردازش، خروجی
صورت مسئله: کاربر عنوان و مبلغ را وارد میکند؛ برنامه مجموع را با بودجه مقایسه میکند. واحد همه مبلغها تومان است؛ هزینه منفی نداریم؛ مجموع فهرست خالی صفر است و برابری بودجه یک حالت مستقل.
- ورودیعنوان + مبلغ + بودجه
- پردازشاعتبارسنجی → جمع → مقایسه
- خروجیگزارش هزینه و وضعیت بودجه
مرحله اول: متغیر و یک هزینه
عنوان متن است، پس string میخواهد. مبلغ از نوع decimal است؛ مناسب محاسبات دهدهی، با پسوند m. فعلاً مقدارها ثابتاند:
string title = "Food";
decimal amount = 250000m;
decimal budget = 300000m;
Console.WriteLine($"{title}: {amount} toman | Budget: {budget}");تمرین: عنوان را به «کتاب» و مبلغ را به ۱۸۰۰۰۰ تغییر بده. معیار عبور: بدون حفظکردن نمونه، سه متغیر تازه بساز و توضیح بده چرا عنوان و مبلغ نوع یکسانی ندارند.
شرط: کمتر، برابر یا بیشتر از بودجه
برای هزینه ۲۵۰۰۰۰، بودجههای ۳۰۰۰۰۰، ۲۵۰۰۰۰ و ۲۰۰۰۰۰ را امتحان کن. خروجی هر شاخه را پیشبینی کن، سپس برنامه را اجرا کن:
decimal total = 250000m;
decimal budget = 250000m;
if (total < budget)
Console.WriteLine("Under budget");
else if (total == budget)
Console.WriteLine("Exactly on budget");
else
Console.WriteLine("Over budget");خروجی Console.ReadLine متن است. decimal.TryParse موفقیت تبدیل آن به عدد را بررسی میکند. سپس باید اعتبار مبلغ را بسنجیم: منفی، عدد است اما هزینه معتبر نیست.
using System.Globalization;
Console.Write("Amount in toman: ");
string? input = Console.ReadLine();
if (decimal.TryParse(input, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint,
CultureInfo.InvariantCulture, out decimal amount) && amount >= 0)
Console.WriteLine($"Valid: {amount}");
else
Console.WriteLine("Enter a non-negative number using English digits, no commas.");عددها را انگلیسی، بدون ویرگول و با نقطه اعشار وارد کن. نسخه نهایی تا دریافت مبلغ معتبر دوباره سؤال میکند. پشتیبانی از رقم فارسی، تمرین بعدی تو باشد.
مرحله دوم: چند هزینه و حلقه واقعی
فرض کن چهار هزینه داریم: غذا ۲۵۰۰۰۰، رفتوآمد ۱۲۰۰۰۰، خرید ۳۴۰۰۰۰ و اجاره ۷۰۰۰۰۰ تومان. قرار نیست برای هر هزینه یک خط جمع جدا بنویسیم. ابتدا مبلغها را داخل List<decimal> قرار میدهیم؛ سپس حلقه foreach تکتک آنها را به مجموع اضافه میکند:
List<decimal> amounts = new List<decimal>
{
250000m, // Food
120000m, // Transport
340000m, // Shopping
700000m // Rent
};
decimal total = 0;
foreach (decimal amount in amounts)
{
total += amount;
}
Console.WriteLine(total); // 1410000مجموع بعد از هر دور بهترتیب ۲۵۰۰۰۰، ۳۷۰۰۰۰، ۷۱۰۰۰۰ و ۱۴۱۰۰۰۰ تومان میشود. فعلاً نوشتن همین حلقه از استفاده فوری از میانبرهایی مثل Sum آموزندهتر است: میبینی پاسخ چگونه ساخته میشود. اگر فهرست خالی باشد، حلقه اجرا نمیشود و مقدار اولیه صفر باقی میماند.
تمرین: مبلغ ۹۰۰۰۰ را با Add اضافه کن؛ مجموع باید ۱۵۰۰۰۰۰ شود. دوباره گزارش بگیر. اگر نتیجه دوبرابر شد، بررسی کن آیا متغیر مجموع را قبل از محاسبه از صفر شروع کردهای. معیار عبور، جواب درست برای تعداد متغیر هزینههاست، نه فقط همان چهار عدد نمونه.
مرحله سوم: تابع و مدل داده
وقتی همه کارها داخل یک حلقه بزرگ هستند، تغییر ساده هم دشوار میشود. تابع به یک بخش کد نام و مسئولیت میدهد. AddExpense ورودی معتبر را به فهرست اضافه میکند؛ CalculateTotal فهرست میگیرد و مجموع برمیگرداند؛ ShowReport فهرست و بودجه میگیرد و گزارش چاپ میکند. تابع محاسبه نباید برای جمعزدن، دوباره از کاربر سؤال بپرسد.
کلاس Expense عنوان و مبلغ را کنار هم نگه میدارد. کلاس، الگوست؛ هر شیء، یک هزینه مشخص. پس از ساخت یک شیء، آن را به فهرست اضافه میکنیم:
Expense food = new Expense { Title = "Food", Amount = 250000m };
List<Expense> expenses = new List<Expense>();
expenses.Add(food);
Console.WriteLine($"{expenses[0].Title}: {expenses[0].Amount}");
public class Expense
{
public string Title { get; set; } = "";
public decimal Amount { get; set; }
}در نسخه نهایی ویژگی Category هم برای یک تمرین کوچک اضافه شده است. ورودی تابع محاسبه، فهرستی از همین هزینههاست. خروجی آن فقط عدد است؛ چاپ و تصمیم بودجه مسئولیت گزارش باقی میماند:
static decimal CalculateTotal(List<Expense> expenses)
{
decimal total = 0;
foreach (Expense expense in expenses)
total += expense.Amount;
return total;
}معیار عبور: ورودی و خروجی هر تابع را توضیح بده و تغییر کوچکی بدون خرابشدن منو انجام بده. فعلاً ارثبری و معماری چندلایه لازم نیست.
مرحله چهارم: داده بعد از بستن برنامه باقی بماند
فهرست داخل حافظه با پایان اجرای برنامه از بین میرود. در روزهای پایانی با System.Text.Json آن را به متن JSON تبدیل و داخل expenses.json ذخیره میکنیم؛ اجرای بعد همان فایل را به فهرست تبدیل میکند. برای این هدف، دیتابیس لازم نیست. مستند رسمی ذخیره JSON در C# توضیح تکمیلی این مرحله است.
نبودن فایل در اولین اجرا طبیعی است؛ خراببودن فایل موجود نیست. نمونه در حالت دوم متوقف میشود تا داده خالی جای فایل اصلی ننشیند. پیش از بررسی فایل خراب، نسخه پشتیبان بگیر.
برنامه تمرینی ۳۰ روز اول C#
کارت را باز کن، تمرین کن و معیار پایان را بسنج. اگر هنوز مستقل نیستی، همان روز را تکرار کن. نمونه کامل برای مقایسه بعد از تلاش خودت است.
- روز ۱ تا ۱۰فهم مسئله، نصب، متغیر و شرط
- روز ۱۱ تا ۲۰حلقه، مجموعه، منو و تابع
- روز ۲۱ تا ۲۵مدل داده، گزارش و تست
- روز ۲۶ تا ۳۰فایل، بازیابی و تحویل پروژه
روز ۱ · صورت مسئله قبل از کد
تمرینثبت هزینههای روزانه را روی کاغذ تعریف کن: عنوان، مبلغ به تومان، بودجه و گزارش مجموع.
خروجییک برگه با ورودی، پردازش و خروجی و دو نمونه عددی.
معیار پایانبدون نامبردن از دستورهای C#، رفتار برنامه و واحد پول را توضیح میدهی.
روز ۲ · نصب و اولین اجرا
تمرینSDK را نصب کن؛ پروژه GoljaamExpenseTracker را بساز و پیام آغاز آن را در Program.cs تغییر بده.
خروجیاجرای dotnet run و نمایش پیام اختصاصی خودت.
معیار پایاناز پوشه درست اجرا میکنی و تفاوت SDK با Runtime را میدانی.
روز ۳ · متغیر و نوع داده
تمرینعنوان هزینه را در string و مبلغ و بودجه را در decimal قرار بده؛ سه مقدار را چاپ کن.
خروجیسه مقدار با نامهای قابلفهم و واحد تومان.
معیار پایاندلیل استفاده از decimal و پسوند m را توضیح میدهی.
روز ۴ · ورودی و خروجی
تمرینعنوان را با Console.ReadLine بگیر و یک پیام با Console.WriteLine نمایش بده.
خروجیعنوانی که خودت وارد کردهای در خروجی دیده میشود.
معیار پایانتفاوت ورودی کاربر با متن ثابت داخل کد را میشناسی.
روز ۵ · ثبت یک هزینه
تمرینعنوان را از ورودی بگیر؛ فعلاً مبلغ ثابت 250000 باشد. گزارش عنوان و مبلغ را بساز.
خروجیگزارش یک هزینه، بدون شرط و حلقه.
معیار پایانبا تغییر عنوان و مبلغ، خروجی درست تغییر میکند.
روز ۶ · شرط بودجه
تمرینبا if و else مجموع یک هزینه را با بودجه مقایسه کن؛ پیام کمبودن یا بیشتربودن را بساز.
خروجیپیامی متناسب با هزینه کمتر یا بیشتر از بودجه.
معیار پایانقبل از اجرا برای دو ورودی، خروجی را درست پیشبینی میکنی.
روز ۷ · حالت برابر
تمرینشاخه برابری را جدا کن؛ بودجههای 300000، 250000 و 200000 را برای هزینه 250000 امتحان کن.
خروجیسه پیام متمایز: کمتر، برابر، بیشتر.
معیار پایانمرز برابری اشتباهاً وارد شاخه کمتر یا بیشتر نمیشود.
روز ۸ · ورودی نامعتبر
تمرینبرای عنوان خالی و مبلغ منفی شرط بگذار؛ با عملگرهای منطقی یک بازه مجاز تعریف کن.
خروجیورودی ناسالم پذیرفته نمیشود و دلیل آن مشخص است.
معیار پایانبا عنوان فقط فاصله و مقدار منفی هم رفتار درست میبینی.
روز ۹ · تبدیل امن با TryParse
تمرینمبلغ را از کاربر بگیر؛ برای متن abc یا عدد خارج از بازه پیام راهنما بده.
خروجیعدد معتبر تبدیل میشود؛ ورودی اشتباه برنامه را نمیبندد.
معیار پایانمیدانی موفقیت تبدیل و معتبربودن مبلغ دو بررسی جدا هستند.
روز ۱۰ · مرور بدون کپی
تمریناز پروژه خالی، نسخه تکهزینهای با عنوان، مبلغ و مقایسه بودجه را دوباره بنویس.
خروجیبرنامه کوچکی که بدون دیدن راهحل قبلی اجرا میشود.
معیار پایانهر خط را توضیح میدهی؛ اگر گیر کردی فقط Hint میگیری.
روز ۱۱ · حلقه و تکرار
تمرینبا حلقه سه عنوان هزینه بگیر؛ تعداد اجراها را قبل از اجرای برنامه روی کاغذ بنویس.
خروجیسه ورودی و سه خروجی، بدون تکرار دستی کد.
معیار پایانشرط ادامه و زمان پایان حلقه را میشناسی.
روز ۱۲ · تکرار تا خروج
تمرینورودی را تا فرمان 0 ادامه بده؛ برای گزینه ناشناخته پیام بده.
خروجیبرنامه با درخواست کاربر متوقف میشود.
معیار پایانحلقه بینهایت ناخواسته نداری و خروج بدون ثبت داده اضافی است.
روز ۱۳ · مجموعه مبلغها
تمرینچهار مبلغ مثال مقاله را داخل List<decimal> قرار بده و تعدادشان را نشان بده.
خروجییک مجموعه با چهار عضو که امکان افزودن عضو دارد.
معیار پایانفرق یک مبلغ با فهرستی از مبلغها را توضیح میدهی.
روز ۱۴ · محاسبه با foreach
تمرینمجموع را از صفر شروع کن و در foreach هر مبلغ را به آن اضافه کن؛ فعلاً از Sum استفاده نکن.
خروجیمجموع دقیق 1410000 تومان برای چهار هزینه.
معیار پایانمقدار متغیر total را بعد از هر دور روی کاغذ حساب میکنی.
روز ۱۵ · افزودن و محاسبه مجدد
تمرینهزینه تازه 90000 را اضافه کن و گزارش را دوباره بساز؛ دوبار هم گزارش بگیر.
خروجیمجموع جدید 1500000 تومان است و گزارش دوم آن را دوبرابر نمیکند.
معیار پایانمحاسبه از صفر آغاز میشود و نتیجه قبلی دوباره جمع نمیشود.
روز ۱۶ · فهرست خالی و مرزها
تمرینگزارش مجموعه خالی، هزینه صفر و عدد خارج از سقف آموزشی را آزمایش کن.
خروجیمجموع خالی صفر است؛ ورودی خارج از محدوده رد میشود.
معیار پایانهیچکدام از این سه حالت باعث توقف غیرمنتظره برنامه نیست.
روز ۱۷ · منوی ساده
تمرینگزینههای افزودن، نمایش گزارش و خروج را یکپارچه کن؛ گزینه 9 را هم امتحان کن.
خروجیمنویی تکرارشونده با سه رفتار مشخص.
معیار پایاندیدن گزارش هزینهای اضافه نمیکند و گزینه اشتباه قابل اصلاح است.
روز ۱۸ · تابع و مسئولیت
تمرینبخش محاسبه مجموع را به CalculateTotal تبدیل کن؛ ورودی و خروجی آن را بنویس.
خروجیتابعی که فهرست میگیرد و عدد برمیگرداند.
معیار پایانتابع محاسبه برای کار خود از کاربر ورودی نمیگیرد.
روز ۱۹ · تقسیم کار بین توابع
تمرینAddExpense و ShowReport را جدا کن؛ مسیر فراخوانیها را با سه پیکان رسم کن.
خروجیمنوی خواناتر با توابع کوچکتر.
معیار پایانمیگویی کدام تابع داده را تغییر میدهد و کدام فقط گزارش میکند.
روز ۲۰ · بازبینی نسخه اول
تمریننامهای مبهم را عوض کن؛ سناریوهای روزهای ۷، ۹ و ۱۶ را بعد از مرتبسازی دوباره اجرا کن.
خروجینسخهای خواناتر با همان خروجیهای درست.
معیار پایاناصلاح ظاهری کد رفتار قبلی را خراب نکرده است.
روز ۲۱ · مدل Expense
تمرینکلاس Expense با Title و Amount بساز؛ یک نمونه ایجاد و ویژگیهایش را چاپ کن.
خروجیعنوان و مبلغ یک هزینه در یک شیء کنار هماند.
معیار پایانفرق کلاس بهعنوان الگو و شیء ساختهشده از آن را توضیح میدهی.
روز ۲۲ · فهرست هزینههای واقعی
تمریناز List<Expense> استفاده کن و چهار هزینه را با عنوان و مبلغ ثبت کن.
خروجیهر ردیف عنوان و مبلغ مربوط به همان هزینه را دارد.
معیار پایاندیگر دو فهرست جدا و شکننده برای عنوانها و مبلغها نداری.
روز ۲۳ · گزارش خوانا
تمرینعنوان، مبلغ با جداکننده هزارگان و واحد تومان را نشان بده؛ در پایان مجموع و وضعیت بودجه را چاپ کن.
خروجیگزارشی که فرد دیگری هم بتواند آن را بخواند.
معیار پایاناعداد نمایشی درستاند و واحد پول در تمام خروجی یکسان است.
روز ۲۴ · تغییر کوچک مستقل
تمرینویژگی Category را اضافه کن؛ مقدار خالی آن را Other بگذار و در گزارش نمایش بده.
خروجیهزینه جدید با دستهبندی ساده، بدون پیچیدهکردن منو.
معیار پایاناین تغییر را بدون دریافت نسخه کامل اصلاحشده انجام دادهای.
روز ۲۵ · سناریو و دیباگ
تمرینبرای عنوان خالی، مبلغ منفی، بودجه برابر و چند هزینه، انتظار و نتیجه واقعی را ثبت کن.
خروجیچهار سناریوی نوشتهشده با نتیجه قبول یا نیازمند اصلاح.
معیار پایانیک خطا را با ورودی قابل تکرار توضیح میدهی، نه فقط «کار نمیکند».
روز ۲۶ · آشنایی با فایل
تمریندر پوشه تمرین یک فایل متنی آزمایشی بساز و بخوان؛ مفهوم مسیر جاری را بررسی کن.
خروجیمتنی که بعد از بستن و بازکردن برنامه باقی میماند.
معیار پایانمسیر ذخیره را میدانی و روی فایل شخصی یا واقعی آزمایش نمیکنی.
روز ۲۷ · ذخیره JSON
تمرینفهرست Expenseها را با System.Text.Json ذخیره کن؛ فایل ساختهشده را با ویرایشگر باز کن.
خروجیفایل JSON دارای عنوان، مبلغ و دسته هر هزینه.
معیار پایانذخیره موفق را با وجود فایل و محتوای درست آن تأیید میکنی.
روز ۲۸ · بازیابی داده
تمریندر ابتدای اجرا فایل را بخوان؛ برنامه را ببند و دوباره از همان پوشه اجرا کن.
خروجیهزینههای اجرای قبل دوباره در گزارش دیده میشوند.
معیار پایاندادههای قبلی دوباره ثبت یا دوبرابر نشدهاند.
روز ۲۹ · فایل گمشده و خراب
تمریندر پوشه تست، یکبار بدون فایل و یکبار با JSON خراب اجرا کن؛ پیش از خرابکردن کپی بگیر.
خروجیفایل گمشده یعنی شروع خالی؛ فایل خراب یعنی پیام و توقف امن.
معیار پایانبرنامه فایل خراب را با فهرست خالی بازنویسی نمیکند.
روز ۳۰ · تحویل و چالش بعدی
تمرینREADME، دستور اجرا و محدودیتها را بنویس؛ سپس جمع هزینههای یک دسته را بدون کپی اضافه کن.
خروجیپروژه اجراشدنی، راهنمای استفاده و یک قابلیت مستقل.
معیار پایاندیگری پروژه را اجرا میکند و تو منطق، تستها و تغییر تازه را توضیح میدهی.
برنامه را برای تمرین کنار دستت نگه دار
فایل فارسی شامل همه ۳۰ روز، خروجی مورد انتظار و معیار پایان هر روز، چکلیست سنجش و صفحه یادداشت است. دانلود مستقیم و رایگان است.
دانلود برنامه ۳۰روزه PDFنسخه نهایی پروژه و راهحل نمونه
نسخه کامل را زود باز نکن. اول منو، افزودن هزینه و گزارش خودت را بساز؛ بعد تفاوتها را بررسی کن. پیامهای نمونه برای سازگاری با ترمینالهای مختلف انگلیسیاند؛ عنوان فارسی قابل ثبت است. همه مبلغها تومان هستند. بودجه در شروع هر اجرا دوباره پرسیده میشود و فقط هزینهها ذخیره میشوند.
پروژه دانلودی وابستگی جانبی ندارد. فایل ZIP را در پوشه تمرین باز کن و دستور dotnet run را همانجا اجرا کن. فایل داده در پوشه جاری ساخته میشود؛ برای بازیابی، اجرای بعد را از همان پوشه انجام بده. این نمونه آموزشی تککاربره است؛ آن را همزمان در چند پنجره یا برای اطلاعات مالی حساس استفاده نکن.
راهحل نمونه؛ بعد از تلاش خودت ببین
سقف آموزشی هر مبلغ یک تریلیون تومان و تعداد رکوردها دههزار است تا ورودیهای غیرعادی نیز محدود باشند. صفر مجاز و منفی نامجاز است. ذخیره ابتدا در فایل موقت تکمیل میشود، سپس جای فایل اصلی را میگیرد.
دانلود پروژه کامل C# و راهنمای اجراusing System.Globalization;
using System.Text;
using System.Text.Json;
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
const string filePath = "expenses.json";
List<Expense> expenses;
try
{
expenses = File.Exists(filePath)
? JsonSerializer.Deserialize<List<Expense>>(File.ReadAllText(filePath))
?? throw new JsonException("Expected a list.")
: new List<Expense>();
if (expenses.Count > 10000 || expenses.Any(e => e == null
|| string.IsNullOrWhiteSpace(e.Title) || e.Title.Length > 100
|| string.IsNullOrWhiteSpace(e.Category) || e.Category.Length > 50
|| e.Amount < 0 || e.Amount > 1_000_000_000_000m))
throw new JsonException("Invalid expense data.");
}
catch (Exception ex) when (ex is JsonException or IOException or UnauthorizedAccessException)
{
Console.WriteLine("Cannot load expenses.json. Original file was NOT changed.");
Console.WriteLine("Back it up, then inspect or repair it before running again.");
return;
}
Console.WriteLine("Goljaam Expense Tracker | amounts in toman");
decimal? budgetInput = ReadAmount("Budget: ");
if (budgetInput == null) return;
decimal budget = budgetInput.Value;
while (true)
{
Console.WriteLine("1 Add expense | 2 Show report | 0 Exit");
string? choice = Console.ReadLine();
if (choice == null || choice == "0") break;
if (choice == "1")
{
if (!AddExpense(expenses)) continue;
try
{
string json = JsonSerializer.Serialize(expenses,
new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(filePath + ".tmp", json, Encoding.UTF8);
File.Move(filePath + ".tmp", filePath, overwrite: true);
Console.WriteLine("Saved.");
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
{
Console.WriteLine("Save failed. Do not assume the new expense was saved.");
return;
}
ShowReport(expenses, budget);
}
else if (choice == "2") ShowReport(expenses, budget);
else Console.WriteLine("Choose 0, 1 or 2.");
}
static decimal? ReadAmount(string prompt)
{
while (true)
{
Console.Write(prompt);
string? text = Console.ReadLine();
if (text == null) return null;
if (decimal.TryParse(text, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint,
CultureInfo.InvariantCulture, out decimal amount)
&& amount >= 0 && amount <= 1_000_000_000_000m)
return amount;
Console.WriteLine("Enter 0..1000000000000 using English digits, no commas.");
}
}
static bool AddExpense(List<Expense> expenses)
{
if (expenses.Count >= 10000)
{
Console.WriteLine("Practice limit: 10000 expenses.");
return false;
}
Console.Write("Title: ");
string? title = Console.ReadLine()?.Trim();
if (string.IsNullOrWhiteSpace(title) || title.Length > 100)
{
Console.WriteLine("Title must contain 1..100 characters.");
return false;
}
decimal? amount = ReadAmount("Amount: ");
if (amount == null) return false;
Console.Write("Category (Enter = Other): ");
string category = Console.ReadLine()?.Trim() ?? "";
if (category.Length > 50)
{
Console.WriteLine("Category is too long.");
return false;
}
expenses.Add(new Expense
{
Title = title,
Amount = amount.Value,
Category = category.Length == 0 ? "Other" : category
});
return true;
}
static decimal CalculateTotal(List<Expense> expenses)
{
decimal total = 0;
foreach (Expense expense in expenses)
total += expense.Amount;
return total;
}
static void ShowReport(List<Expense> expenses, decimal budget)
{
if (expenses.Count == 0) Console.WriteLine("No expenses yet.");
foreach (Expense expense in expenses)
Console.WriteLine($"{expense.Title} | {expense.Amount.ToString("N0", CultureInfo.InvariantCulture)} toman | {expense.Category}");
decimal total = CalculateTotal(expenses);
Console.WriteLine($"Total: {total.ToString("N0", CultureInfo.InvariantCulture)} toman");
if (total < budget) Console.WriteLine("Under budget");
else if (total == budget) Console.WriteLine("Exactly on budget");
else Console.WriteLine("Over budget");
}
public class Expense
{
public string Title { get; set; } = "";
public decimal Amount { get; set; }
public string Category { get; set; } = "Other";
}

برای تست، تنها مسیر موفق را اجرا نکن: فهرست خالی، عنوان خالی، متن بهجای عدد، مبلغ منفی، بودجه دقیقاً برابر مجموع، فایل گمشده، فایل خراب و بازکردن مجدد برنامه هم مهماند. در فایل خراب باید پیام خطا ببینی و فایل بدون تغییر باقی بماند؛ در اجرای مجدد باید همان چهار هزینه برگردند.
از کجا بفهمم واقعاً یاد گرفتهام؟
بدون نگاهکردن به نمونه، به این پرسشها پاسخ بده. اگر فقط جای خطها را حفظ کردهای اما دلیلشان را نمیدانی، یک تمرین کوچکتر را دوباره بساز. هدف این چکلیست سرزنشکردن نیست؛ پیداکردن قدم بعدی است.
- میتوانم مسیر ورودی تا گزارش را با زبان خودم توضیح بدهم.
- میتوانم مقدارهای حلقه و سه حالت بودجه را قبل از اجرا پیشبینی کنم.
- میتوانم ورودی نامعتبر را بدون بستهشدن ناگهانی برنامه مدیریت کنم.
- میتوانم یک ویژگی مثل دستهبندی را مستقل تغییر بدهم.
- میدانم داده کجا ذخیره میشود و فایل خراب چرا نباید بازنویسی شود.
- میتوانم فردا یک نسخه کوچک مشابه را بدون کپی دوباره بسازم.
از هوش مصنوعی برای Hint، طراحی تست یا بررسی تلاش خودت کمک بگیر؛ نه برای تحویلگرفتن پروژهای که نمیتوانی توضیحش بدهی. مثلاً بپرس: «چرا مجموع من بعد از گزارش دوم دوبرابر میشود؟ فقط یک راهنمایی بده.» برای نمونههای بیشتر، ۲۰ پرامپت کاربردی برای برنامهنویسها را ببین.
بعد از ۳۰ روز چه چیزی یاد بگیرم؟
اگر پروژه را مستقل اجرا و تغییر میدهی، شیءگرایی را عمیقتر کن، با Git ثبت نسخهها را یاد بگیر و تستنویسی را ادامه بده. برای مسیر وب، بعد از آشنایی با HTTP و مبانی HTML/CSS، سراغ SQL و سپس ASP.NET Core برو. لازم نیست همه اینها را در ماه اول کنار هم شروع کنی. نقشه راه پروژهمحور ASP.NET Core تصویر ادامه مسیر را نشان میدهد.
تمرین بعدی میتواند مدیریت کتابهای شخصی یا فهرست کارها باشد؛ همان ورودی، مجموعه، گزارش و فایل را در مسئلهای متفاوت پیاده کن. اگر میخواهی پروژه را قابل ارائه کنی، راهنمای ساخت نمونهکار برنامهنویسی به انتخاب دامنه و مستندسازی کمک میکند. آمادهبودن برای کار حرفهای به تمرین بیشتر، کیفیت پروژه، همکاری و نیاز موقعیت شغلی وابسته است، نه فقط تمامکردن این تقویم.
پرسشهای متداول شروع برنامهنویسی با C#
اگر کاملاً از صفر شروع کنم، این مسیر مناسب است؟
بله؛ به دانش قبلی C# نیاز ندارد. کار معمول با پوشهها و نصب نرمافزار کافی است. اگر همان نصب زمان بیشتری گرفت، روز دوم را تکرار کن؛ از تمرین مستقل صرفنظر نکن.
آیا بعد از ۳۰ روز آماده استخدام میشوم؟
این برنامه چنین وعدهای نمیدهد. خروجی آن یک پروژه کوچک و پایه حل مسئله است. برای استخدام، عمق مهارت، تجربه پروژه، همکاری و انتظارات کارفرما هم اهمیت دارند.
روزانه چقدر وقت لازم است؟
۶۰ تا ۹۰ دقیقه پیشنهاد میشود. با زمان کمتر هم میتوانی ادامه بدهی؛ برنامه را طولانیتر کن و معیار پایان هر روز را نگه دار.
میتوانم از همان اول ASP.NET یاد بگیرم؟
برای این مسیر بهتر است ابتدا ورودی، شرط، حلقه، تابع و مدل داده را در کنسول تمرین کنی. بعد، یادگیری وب و ASP.NET روی پایه روشنتری قرار میگیرد.
برای پروژه ثبت هزینه دیتابیس لازم است؟
خیر. برای نسخه تککاربره آموزشی، فایل JSON کافی است. دیتابیس را زمانی اضافه کن که مسئله و پیشنیازهایش را میشناسی، نه صرفاً برای بزرگترشدن پروژه.
استفاده از AI در این تمرینها مجاز است؟
بله، برای توضیح، Hint و بازبینی. قبل از گرفتن پاسخ کامل تلاش کن؛ بعد هم تمرینی شبیه آن را بدون کمک بازسازی کن تا وابسته به پاسخ آماده نمانی.
اگر از برنامه عقب افتادم چه کنم؟
از آخرین روزی که معیارش را واقعاً انجام دادهای ادامه بده. تمرین کوچکتر، زمانبندی سبکتر و نوشتن سؤال دقیق از فشردهکردن چند روز در یک نشست بهتر است.
پروژه بعدی من چه باشد؟
یک مسئله آشنا مثل مدیریت کتاب یا کارهای روزانه انتخاب کن. ابتدا نسخه کوچک با چند سناریوی تست بساز، سپس یک قابلیت تازه اضافه کن؛ بدون کپی کامل همین کد.
