وبلاگ
شروع برنامهنویسی با C#: اولین گامهای شما
فهرست مطالب
“تسلط به برنامهنویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT”
"تسلط به برنامهنویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT"
"با شرکت در این دوره جامع و کاربردی، به راحتی مهارتهای برنامهنویسی پایتون را از سطح مبتدی تا پیشرفته با کمک هوش مصنوعی ChatGPT بیاموزید. این دوره، با بیش از 6 ساعت محتوای آموزشی، شما را قادر میسازد تا به سرعت الگوریتمهای پیچیده را درک کرده و اپلیکیشنهای هوشمند ایجاد کنید. مناسب برای تمامی سطوح با زیرنویس فارسی حرفهای و امکان دانلود و تماشای آنلاین."
ویژگیهای کلیدی:
بدون نیاز به تجربه قبلی برنامهنویسی
زیرنویس فارسی با ترجمه حرفهای
۳۰ ٪ تخفیف ویژه برای دانشجویان و دانش آموزان
0 تا 100 عطرسازی + (30 فرمولاسیون اختصاصی حامی صنعت)
دوره آموزش Flutter و برنامه نویسی Dart [پروژه محور]
دوره جامع آموزش برنامهنویسی پایتون + هک اخلاقی [با همکاری شاهک]
دوره جامع آموزش فرمولاسیون لوازم آرایشی
دوره جامع علم داده، یادگیری ماشین، یادگیری عمیق و NLP
دوره فوق فشرده مکالمه زبان انگلیسی (ویژه بزرگسالان)
شمع سازی و عودسازی با محوریت رایحه درمانی
صابون سازی (دستساز و صنعتی)
صفر تا صد طراحی دارو
متخصص طب سنتی و گیاهان دارویی
متخصص کنترل کیفی شرکت دارویی
شروع برنامهنویسی با C#: اولین گامهای شما
در دنیای پرشتاب و دائماً در حال تحول برنامهنویسی، انتخاب زبانی قدرتمند و همهکاره برای شروع یا گسترش مهارتهای شما اهمیت ویژهای دارد. C# (سیشارپ)، زبانی مدرن، شیگرا و توسعهیافته توسط مایکروسافت، انتخابی هوشمندانه است که دروازهای به سوی طیف وسیعی از فرصتهای توسعه نرمافزار را برای شما میگشاید. این زبان که عضوی جداییناپذیر از اکوسیستم .NET است، نه تنها برای ساخت برنامههای کاربردی دسکتاپ و وبسایتهای مقیاسپذیر استفاده میشود، بلکه در توسعه بازی، برنامههای موبایل و حتی هوش مصنوعی نیز کاربرد فراوان دارد. اگر به دنبال برداشتن اولین گامهای محکم و مؤثر در مسیر برنامهنویسی هستید یا قصد مهاجرت از زبانی دیگر به C# را دارید، این مقاله راهنمای جامع شما خواهد بود. ما در این مسیر، از نصب ابزارهای لازم گرفته تا درک مفاهیم بنیادی و حتی نگاهی اجمالی به ساختارهای پیشرفتهتر، شما را همراهی خواهیم کرد تا با دیدی روشن و پایهای قوی، سفر برنامهنویسی خود را با C# آغاز کنید.
هدف این مقاله، ارائه یک دیدگاه عمیق و کاربردی برای متخصصان و علاقهمندانی است که میخواهند فراتر از مثالهای ساده «Hello World»، به درکی جامع از C# دست یابند. ما با تمرکز بر جزئیات فنی و ارائه مثالهای کد قابل اجرا، سعی خواهیم کرد تا نه تنها اصول اولیه را آموزش دهیم، بلکه نکات و بهترین شیوههایی را نیز مطرح کنیم که برای یک برنامهنویس حرفهای ضروری است. آماده باشید تا قدم به دنیای قدرتمند C# بگذارید و پتانسیلهای بیکران آن را کشف کنید.
چرا C#؟ بررسی مزایا و کاربردها
پیش از آنکه به جنبههای فنی C# بپردازیم، ضروری است بدانیم چرا این زبان تا این حد در صنعت نرمافزار مورد استقبال قرار گرفته و چه مزایایی آن را به گزینهای ایدهآل برای توسعهدهندگان تبدیل میکند. C# تنها یک زبان برنامهنویسی نیست؛ بلکه یک ابزار قدرتمند در اکوسیستم .NET است که توسط مایکروسافت با هدف ایجاد یک چارچوب توسعه جامع، ایمن و کارآمد طراحی شده است.
جامعیت اکوسیستم .NET
یکی از بزرگترین مزایای C#، پیوستگی آن با پلتفرم .NET است. این پلتفرم شامل طیف وسیعی از کتابخانهها، فریمورکها و ابزارهاست که توسعهدهندگان را قادر میسازد تا انواع مختلفی از برنامههای کاربردی را بسازند. از برنامههای ویندوزی (Windows Forms, WPF) گرفته تا برنامههای وب (ASP.NET Core)، سرویسهای ابری (Azure Functions)، برنامههای موبایل (Xamarin/MAUI) و حتی بازیسازی (Unity)، C# حضور پررنگی دارد. این جامعیت به معنای آن است که با یادگیری C#، شما به دریایی از فرصتها و زمینههای مختلف توسعه دسترسی پیدا میکنید و نیازی به یادگیری زبانهای مختلف برای هر پلتفرم نخواهید داشت.
زبان شیگرا و مدرن
C# یک زبان کاملاً شیگرا (Object-Oriented Programming – OOP) است. این ویژگی به برنامهنویسان کمک میکند تا کدهای ماژولارتر، قابل نگهداریتر و مقیاسپذیرتری بنویسند. مفاهیمی مانند کپسولهسازی (Encapsulation)، وراثت (Inheritance)، چندریختی (Polymorphism) و انتزاع (Abstraction) در C# به طور کامل پیادهسازی شدهاند. علاوه بر این، C# به طور مداوم در حال تکامل است و ویژگیهای مدرنی مانند LINQ (Language Integrated Query)، Async/Await برای برنامهنویسی ناهمگام، و Record Types برای مدلسازی دادهها را ارائه میدهد که نوشتن کدی تمیزتر و کارآمدتر را تسهیل میکند.
عملکرد بالا و مقیاسپذیری
برنامههای نوشته شده با C# و .NET به دلیل کامپایل شدن به زبان میانی (Intermediate Language – IL) و سپس تبدیل به کد ماشین در زمان اجرا (Just-In-Time Compilation – JIT)، عملکرد بسیار خوبی دارند. این بهینهسازیها به همراه قابلیتهای مدیریت حافظه خودکار (Garbage Collection)، C# را به گزینهای مناسب برای توسعه برنامههای کاربردی با کارایی بالا و مقیاسپذیر، مانند سرویسهای Back-End یا سیستمهای پردازش داده، تبدیل کرده است.
ابزارهای توسعه قدرتمند
مایکروسافت ابزارهای توسعه بینظیری را برای C# فراهم کرده است. Visual Studio، محیط توسعه یکپارچه (IDE) پیشرو برای .NET، با قابلیتهایی مانند اشکالزدایی (Debugging) پیشرفته، تکمیل خودکار کد (IntelliSense)، ابزارهای تست و مدیریت پروژه، تجربه توسعهدهنده را به شدت بهبود میبخشد. وجود نسخههای رایگان مانند Visual Studio Community، دسترسی به این ابزارهای قدرتمند را برای همه امکانپذیر میسازد.
جامعه فعال و منابع آموزشی فراوان
C# از یک جامعه توسعهدهندگان بسیار بزرگ و فعال بهرهمند است. این بدان معناست که شما به منابع آموزشی فراوان، انجمنهای پشتیبانی، مستندات جامع و مثالهای کد دسترسی خواهید داشت. اگر با مشکلی روبرو شوید، احتمالاً کسی قبلاً آن را تجربه کرده و راه حلی برای آن ارائه داده است. این پشتیبانی جامعهای، فرآیند یادگیری و حل مشکلات را بسیار آسانتر میکند.
کاربردها
- توسعه وب (ASP.NET Core): ساخت وبسایتها و وبسرویسهای قدرتمند و مقیاسپذیر.
- توسعه دسکتاپ (WPF, WinForms, UWP): ایجاد برنامههای کاربردی بومی ویندوز با رابط کاربری غنی.
- توسعه بازی (Unity): یکی از محبوبترین موتورهای بازیسازی جهان، که C# را به عنوان زبان اصلی اسکریپتنویسی خود پشتیبانی میکند.
- توسعه موبایل (Xamarin/MAUI): ساخت برنامههای کراسپلتفرم برای iOS، Android و Windows از یک پایگاه کد واحد.
- خدمات ابری (Azure): توسعه و استقرار سرویسهای ابری و میکروسرویسها بر روی پلتفرم Microsoft Azure.
- هوش مصنوعی و یادگیری ماشین: با استفاده از ML.NET، توسعهدهندگان میتوانند مدلهای یادگیری ماشین را با C# بسازند و به کار گیرند.
با توجه به این مزایا و کاربردهای گسترده، انتخاب C# برای شروع یا ادامه مسیر برنامهنویسی، یک سرمایهگذاری هوشمندانه در آینده حرفهای شماست.
آمادهسازی محیط توسعه: Visual Studio و .NET SDK
قبل از آنکه بتوانیم حتی یک خط کد C# بنویسیم، نیاز داریم که محیط توسعه مناسب را بر روی سیستم خود نصب و پیکربندی کنیم. ابزار اصلی که برای این منظور استفاده خواهیم کرد، Visual Studio است. Visual Studio یک محیط توسعه یکپارچه (IDE) کامل است که نه تنها امکان کدنویسی، بلکه اشکالزدایی، تست، مدیریت پروژه و بسیاری قابلیتهای دیگر را فراهم میآورد. همچنین به .NET SDK (Software Development Kit) نیاز داریم که شامل کامپایلر C# و کتابخانههای مورد نیاز برای ساخت و اجرای برنامههای .NET است.
نصب Visual Studio
Visual Studio در نسخههای مختلفی عرضه میشود، از جمله Community (رایگان برای دانشجویان، پروژههای منبع باز و تیمهای کوچک)، Professional و Enterprise. برای شروع، نسخه Community کاملاً کافی و ایدهآل است.
- دانلود Visual Studio Installer: به وبسایت رسمی مایکروسافت برای Visual Studio (https://visualstudio.microsoft.com/downloads/) مراجعه کرده و نسخه Community را دانلود کنید.
- اجرای Installer: فایل دانلود شده (.exe) را اجرا کنید. این فایل، Visual Studio Installer است که به شما امکان میدهد اجزای مورد نیاز Visual Studio را انتخاب و نصب کنید.
-
انتخاب Workloads: در حین فرآیند نصب، با صفحهای مواجه میشوید که از شما میخواهد “Workloads” (مجموعههای کاری) مورد نیازتان را انتخاب کنید. Workload ها شامل مجموعهای از ابزارها و SDK های لازم برای توسعه در زمینههای خاص هستند. برای توسعه با C#، حداقل Workload های زیر را انتخاب کنید:
- .NET desktop development: برای توسعه برنامههای دسکتاپ ویندوز.
- ASP.NET and web development: برای توسعه وبسایتها و وبسرویسها با ASP.NET Core.
- Game development with Unity: اگر قصد توسعه بازی دارید.
- Mobile development with .NET: برای توسعه برنامههای موبایل با MAUI/Xamarin.
برای شروع و اهداف این مقاله، انتخاب “.NET desktop development” و “ASP.NET and web development” توصیه میشود. همچنین میتوانید در بخش “Individual components” موارد خاصی مانند نسخههای مختلف .NET SDK را نیز انتخاب کنید، اما معمولاً انتخاب Workload ها کافی است زیرا SDK های مربوطه را به صورت خودکار نصب میکنند.
- نصب: پس از انتخاب Workload ها، روی دکمه “Install” کلیک کنید. این فرآیند ممکن است بسته به سرعت اینترنت و قدرت سیستم شما زمانبر باشد.
پس از اتمام نصب، Visual Studio آماده استفاده است. میتوانید آن را از منوی Start ویندوز یا با جستجو برای “Visual Studio” اجرا کنید.
بررسی نصب .NET SDK
.NET SDK به صورت خودکار با نصب Workload های مربوطه در Visual Studio نصب میشود، اما میتوانید برای اطمینان از نصب صحیح و مشاهده نسخههای نصب شده، این مراحل را دنبال کنید:
- باز کردن Command Prompt/PowerShell: کلید Windows + R را فشار دهید، سپس “cmd” را تایپ کرده و Enter را بزنید (یا “powershell” را تایپ کنید).
-
اجرای دستور .NET: در پنجره Command Prompt/PowerShell، دستور زیر را تایپ کرده و Enter را بزنید:
dotnet --info
- بررسی خروجی: این دستور اطلاعاتی در مورد نسخههای .NET SDK و .NET Runtime نصب شده بر روی سیستم شما را نمایش میدهد. اگر SDK به درستی نصب شده باشد، بخشی با عنوان “.NET SDKs” و لیست نسخههای نصب شده را مشاهده خواهید کرد.
یکپارچهسازی محیط توسعه (IDE)
Visual Studio پس از نصب، آماده استفاده است. هنگام باز کردن آن برای اولین بار، ممکن است از شما خواسته شود تا با حساب مایکروسافت خود وارد شوید (اختیاری اما توصیه میشود) و یک طرح رنگی برای IDE انتخاب کنید. پس از آن، میتوانید شروع به ایجاد پروژههای جدید کنید. Visual Studio تمامی ابزارهای لازم را برای کامپایل، اشکالزدایی و اجرای کدهای C# شما فراهم میکند.
با آمادهسازی این محیط، شما اکنون ابزارهای لازم را برای شروع برنامهنویسی با C# در اختیار دارید. در بخش بعدی، اولین برنامه C# خود را خواهیم نوشت و ساختار اساسی آن را بررسی خواهیم کرد.
اولین برنامه C#: Hello World و درک ساختار پایه
همانند رسم هر زبان برنامهنویسی، اولین گام در C# نیز با نوشتن برنامه کلاسیک “Hello World!” برداشته میشود. این برنامه سادهترین راه برای درک ساختار پایه یک برنامه C# و مشاهده فرآیند کامپایل و اجرا است. در ادامه، نحوه ایجاد این برنامه و تحلیل هر بخش از آن را توضیح میدهیم.
ایجاد پروژه Hello World در Visual Studio
- باز کردن Visual Studio: Visual Studio را اجرا کنید.
- ایجاد پروژه جدید: در صفحه شروع (Start window)، گزینه “Create a new project” را انتخاب کنید.
- انتخاب قالب پروژه: در پنجره “Create a new project”، در قسمت زبانها (Languages) “C#” و در قسمت پلتفرمها (Platforms) “Windows” و در قسمت نوع پروژه (Project types) “Console” را انتخاب کنید. سپس قالب “Console App” را انتخاب کرده و روی “Next” کلیک کنید.
-
پیکربندی پروژه:
- Project name: یک نام برای پروژه خود انتخاب کنید، مثلاً “HelloWorldApp”.
- Location: مسیری برای ذخیره پروژه خود انتخاب کنید.
- Solution name: نامی برای Solution (مجموعه پروژهها) که میتواند همان نام پروژه باشد.
- Place solution and project in the same directory: این گزینه را فعال کنید تا ساختار پوشه پروژه سادهتر شود.
روی “Next” کلیک کنید.
- انتخاب چارچوب (Framework): نسخه .NET (مثلاً .NET 8.0) را انتخاب کنید. این آخرین نسخه پایدار و توصیه شده است. روی “Create” کلیک کنید.
Visual Studio یک پروژه جدید Console App ایجاد میکند و فایل `Program.cs` را باز میکند. شما باید کدی مشابه زیر را مشاهده کنید (بسته به نسخه .NET ممکن است کمی متفاوت باشد):
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
این سادهترین شکل یک برنامه Hello World در نسخههای جدیدتر .NET است که از ویژگی “top-level statements” استفاده میکند. برای درک بهتر ساختار کلاسیک و کاملتر C#، بیایید آن را به فرمت سنتیتر بازنویسی کنیم:
using System; // 1
namespace HelloWorldApp // 2
{
class Program // 3
{
static void Main(string[] args) // 4
{
Console.WriteLine("Hello, World!"); // 5
}
}
}
تحلیل ساختار پایه برنامه C#
بیایید خط به خط این کد را بررسی کنیم:
-
using System;
این خط یک “Directive” است.
using
به کامپایلر میگوید که فضای نام (namespace) مشخص شده (در اینجاSystem
) را وارد کند. فضای نامSystem
شامل کلاسهای پایهای است که برای کارهای رایج مانند ورودی/خروجی (I/O) کنسول، عملیات ریاضی و غیره استفاده میشوند.Console
که در خط 5 استفاده شده، عضوی از این فضای نام است. -
namespace HelloWorldApp
یک
namespace
(فضای نام) برای سازماندهی کد استفاده میشود. فضاهای نام کمک میکنند تا از تداخل نامها بین کلاسها و انواع مختلف جلوگیری شود، به خصوص در پروژههای بزرگ که شامل کتابخانههای متعدد هستند. همه کلاسها و انواع تعریف شده در یک برنامه معمولاً درون یک فضای نام قرار میگیرند. در اینجا،HelloWorldApp
نام فضای نامی است که برای پروژه ما ایجاد شده است. -
class Program
در C#، هر چیزی (به جز top-level statements در نسخههای جدید) باید درون یک کلاس (
class
) قرار گیرد. یک کلاس یک الگو یا blueprint برای ایجاد اشیاء (objects) است.Program
نام کلاسی است که ما در اینجا تعریف کردهایم. کلاسها شامل متغیرها (fields)، خصوصیات (properties) و توابع (methods) هستند. -
static void Main(string[] args)
این خط متد
Main
را تعریف میکند. متدMain
نقطه ورود (entry point) هر برنامه اجرایی C# است. یعنی زمانی که برنامه شما اجرا میشود، کامپایلر به دنبال این متد میگردد و اجرای برنامه را از اینجا آغاز میکند.static
: کلمه کلیدیstatic
به این معنی است که متدMain
متعلق به خود کلاسProgram
است و نیازی به ایجاد یک شیء از کلاسProgram
برای فراخوانی آن نیست.void
: نشاندهنده نوع بازگشتی متد است.void
به این معنی است که این متد هیچ مقداری را باز نمیگرداند.Main
: نام متد است. این نام خاصی است که توسط C# برای نقطه شروع برنامه شناسایی میشود.(string[] args)
: این بخش پارامترهای ورودی متد را مشخص میکند.args
یک آرایه از رشتهها است که میتواند برای دریافت آرگومانهای خط فرمان (command-line arguments) استفاده شود. در برنامه ساده Hello World، معمولاً از آن استفاده نمیکنیم، اما وجود آن برای متدMain
ضروری است.
-
Console.WriteLine("Hello, World!");
این خط، کار اصلی برنامه ما را انجام میدهد: چاپ متن “Hello, World!” بر روی کنسول.
Console
: یک کلاس در فضای نامSystem
است که امکانات ورودی/خروجی کنسول را فراهم میکند.WriteLine
: یک متدstatic
از کلاسConsole
است که یک خط متن را بر روی کنسول مینویسد و سپس به خط بعدی میرود. متنی که میخواهید نمایش دهید، باید بین پرانتزها و داخل علامتهای نقل قول دوتایی (" "
) قرار گیرد.;
(سمیکولون): هر دستور در C# باید با یک سمیکولون خاتمه یابد. این نشاندهنده پایان یک دستور است.
اجرا کردن برنامه
برای اجرای برنامه در Visual Studio، میتوانید یکی از روشهای زیر را انجام دهید:
- کلید F5 را فشار دهید.
- از منوی “Debug”، گزینه “Start Debugging” را انتخاب کنید.
- روی دکمه “Start” (یک مثلث سبز رنگ) در نوار ابزار کلیک کنید.
پس از اجرا، یک پنجره کنسول سیاه رنگ باز میشود و متن “Hello, World!” را نمایش میدهد. سپس پنجره به طور خودکار بسته میشود، یا اگر در حالت دیباگ باشید، ممکن است پیامی مبنی بر “Press any key to continue…” نمایش داده شود.
با این برنامه ساده، شما نه تنها نحوه نوشتن اولین کد C# خود را یاد گرفتید، بلکه با مفاهیم اساسی مانند فضای نام، کلاسها و متد Main
آشنا شدید. اینها بلوکهای ساختمانی برای هر برنامه پیچیدهتر C# هستند.
مبانی سینتکس C#: متغیرها، انواع داده و عملگرها
پس از ایجاد اولین برنامه، زمان آن فرا رسیده است که به بلوکهای ساختمانی اساسیتر C# بپردازیم: متغیرها، انواع داده و عملگرها. اینها مفاهیمی بنیادی هستند که در هر زبان برنامهنویسی وجود دارند و برای ذخیره، دستکاری و پردازش اطلاعات ضروریاند.
متغیرها (Variables)
یک متغیر، یک مکان نامگذاری شده در حافظه است که برای ذخیره دادهها استفاده میشود. قبل از استفاده از یک متغیر، باید آن را اعلان (declare) کنید. اعلان شامل مشخص کردن نوع دادهای است که متغیر قرار است نگهداری کند و نام آن متغیر.
اعلان و مقداردهی اولیه متغیرها
سینتکس عمومی برای اعلان یک متغیر به صورت زیر است:
نوع_داده نام_متغیر;
میتوانید بلافاصله هنگام اعلان به آن مقدار اولیه بدهید (مقداردهی اولیه):
نوع_داده نام_متغیر = مقدار_اولیه;
مثال:
int age; // اعلان متغیر age از نوع int (عدد صحیح)
age = 30; // مقداردهی به متغیر age
string name = "علی"; // اعلان و مقداردهی اولیه متغیر name از نوع string (رشته)
double price = 19.99; // اعلان و مقداردهی اولیه متغیر price از نوع double (عدد اعشاری)
bool isActive = true; // اعلان و مقداردهی اولیه متغیر isActive از نوع bool (بولی)
کلمه کلیدی `var` (Implicitly Typed Variables)
از C# 3.0 به بعد، میتوانید از کلمه کلیدی var
استفاده کنید تا نوع داده متغیر به طور خودکار توسط کامپایلر بر اساس مقدار اولیه داده شده به آن، استنتاج شود. این کار کد را کوتاهتر و خواناتر میکند، اما فقط زمانی میتوانید از var
استفاده کنید که متغیر را در همان خطی که اعلان میکنید، مقداردهی اولیه کنید.
var counter = 100; // کامپایلر تشخیص میدهد که counter از نوع int است.
var message = "سلام به C#!"; // کامپایلر تشخیص میدهد که message از نوع string است.
var pi = 3.14159; // کامپایلر تشخیص میدهد که pi از نوع double است.
توجه داشته باشید که var
به معنای “ضعیف تایپ شده” (loosely typed) نیست؛ نوع داده در زمان کامپایل تعیین میشود و پس از آن نمیتوانید مقدار دیگری با نوع داده متفاوت به آن متغیر اختصاص دهید.
انواع داده (Data Types)
C# یک زبان “Strongly Typed” است، به این معنی که هر متغیر باید یک نوع داده مشخص داشته باشد. انواع داده در C# به دو دسته اصلی تقسیم میشوند: Value Types و Reference Types.
Value Types (انواع مقداری)
این نوع دادهها مستقیماً مقدار خود را در حافظه ذخیره میکنند. وقتی یک متغیر از نوع مقداری را به متغیر دیگری اختصاص میدهید، یک کپی از مقدار ایجاد میشود. مثالها:
- Integral Types (اعداد صحیح):
sbyte
,byte
: 8-bitshort
,ushort
: 16-bitint
,uint
: 32-bit (شایعترین)long
,ulong
: 64-bit
int num1 = 100; long bigNum = 1234567890123L; // L برای long
- Floating-Point Types (اعداد اعشاری):
float
: 32-bit (با پسوند f/F)double
: 64-bit (پیشفرض برای اعداد اعشاری، شایعترین)decimal
: 128-bit (دقیقتر برای محاسبات مالی، با پسوند m/M)
float temp = 25.5f; double gravity = 9.81; decimal salary = 50000.75m;
- Boolean Type:
bool
: برای ذخیره مقادیرtrue
یاfalse
.
bool isValid = false;
- Character Type:
char
: برای ذخیره یک کاراکتر تکی (مانند ‘A’, ‘b’, ‘7’).
char initial = 'J';
Reference Types (انواع ارجاعی)
این نوع دادهها مقدار خود را مستقیماً در حافظه ذخیره نمیکنند، بلکه یک ارجاع (آدرس) به مکانی در حافظه (Heap) که مقدار واقعی در آن ذخیره شده است را نگه میدارند. وقتی یک متغیر از نوع ارجاعی را به متغیر دیگری اختصاص میدهید، هر دو متغیر به یک مکان حافظه ارجاع میدهند. مثالها:
string
: برای ذخیره دنبالهای از کاراکترها (متن). با اینکهstring
یک کلاس است، رفتار آن در برخی موارد شبیه به Value Type است (immutable).object
: نوع پایه برای تمام انواع در .NET.class
: کلاسهایی که خودتان تعریف میکنید.array
: آرایهها نیز از نوع ارجاعی هستند.
string greeting = "Hello C# Developers!";
object myObject = new object();
int[] numbers = new int[5]; // آرایه از اعداد صحیح
عملگرها (Operators)
عملگرها نمادهایی هستند که به کامپایلر میگویند یک عملیات خاص را بر روی یک یا چند عملوند انجام دهد.
1. عملگرهای حسابی (Arithmetic Operators)
برای انجام محاسبات ریاضی:
+
(جمع)-
(تفریق)*
(ضرب)/
(تقسیم)%
(باقیمانده تقسیم یا Modulo)++
(افزایش یک واحد – Increment)--
(کاهش یک واحد – Decrement)
int a = 10, b = 3;
Console.WriteLine(a + b); // 13
Console.WriteLine(a - b); // 7
Console.WriteLine(a * b); // 30
Console.WriteLine(a / b); // 3 (تقسیم صحیح)
Console.WriteLine(a % b); // 1
a++; // a becomes 11
b--; // b becomes 2
2. عملگرهای انتساب (Assignment Operators)
برای اختصاص دادن یک مقدار به یک متغیر:
=
(انتساب ساده)+=
(جمع و انتساب)-=
(تفریق و انتساب)*=
(ضرب و انتساب)/=
(تقسیم و انتساب)%=
(باقیمانده و انتساب)
int x = 5;
x += 3; // معادل x = x + 3; (x میشود 8)
x *= 2; // معادل x = x * 2; (x میشود 16)
3. عملگرهای مقایسهای (Comparison/Relational Operators)
برای مقایسه دو مقدار و بازگرداندن یک مقدار بولی (true
یا false
):
==
(برابر است با)!=
(نابرابر است با)<
(کوچکتر از)>
(بزرگتر از)<=
(کوچکتر یا مساوی با)>=
(بزرگتر یا مساوی با)
int p = 7, q = 10;
Console.WriteLine(p == q); // False
Console.WriteLine(p < q); // True
Console.WriteLine(p >= 7); // True
4. عملگرهای منطقی (Logical Operators)
برای ترکیب یا معکوس کردن مقادیر بولی:
&&
(Logical AND): اگر هر دو عملوندtrue
باشند، نتیجهtrue
است.||
(Logical OR): اگر حداقل یکی از عملوندهاtrue
باشد، نتیجهtrue
است.!
(Logical NOT): مقدار بولی را معکوس میکند.
bool isSunny = true;
bool isWarm = false;
Console.WriteLine(isSunny && isWarm); // False
Console.WriteLine(isSunny || isWarm); // True
Console.WriteLine(!isSunny); // False
5. عملگرهای دیگر
- عملگر شرطی (Ternary Operator):
? :
یک جایگزین کوتاه برای دستورif-else
.int num = 10; string result = (num > 5) ? "بزرگتر از 5" : "کوچکتر یا مساوی 5"; // result میشود "بزرگتر از 5"
- عملگر Null-Coalescing:
??
برای ارائه یک مقدار پیشفرض در صورتی که یک مقدارnull
باشد.string name = null; string displayName = name ?? "مهمان"; // displayName میشود "مهمان"
- عملگر `is`: برای بررسی اینکه آیا یک شیء از یک نوع خاص است.
object myObject = "Hello"; if (myObject is string) { Console.WriteLine("myObject یک رشته است."); }
درک کامل این مبانی، سنگ بنای نوشتن هر برنامه پیچیدهتری در C# است. با تسلط بر متغیرها، انواع داده و عملگرها، شما آماده ورود به دنیای جریان کنترل برنامه خواهید بود.
جریان کنترل در C#: دستورات شرطی و حلقهها
برنامهها اغلب نیاز دارند که بر اساس شرایط خاص تصمیمگیری کنند و یا مجموعهای از دستورات را چندین بار تکرار کنند. اینجاست که مفاهیم جریان کنترل (Control Flow) وارد میشوند. C# مجموعهای غنی از دستورات شرطی و حلقهها را فراهم میکند که به شما امکان میدهد منطق پیچیدهای را در برنامههای خود پیادهسازی کنید.
دستورات شرطی (Conditional Statements)
دستورات شرطی به برنامه شما اجازه میدهند تا بر اساس اینکه یک شرط خاص true
یا false
است، مسیرهای اجرایی متفاوتی را انتخاب کند.
1. دستور `if-else if-else`
این ساختار پرکاربردترین دستور شرطی است و به شما امکان میدهد چندین شرط را بررسی کنید.
int score = 85;
if (score >= 90)
{
Console.WriteLine("امتیاز شما A است.");
}
else if (score >= 80)
{
Console.WriteLine("امتیاز شما B است.");
}
else if (score >= 70)
{
Console.WriteLine("امتیاز شما C است.");
}
else
{
Console.WriteLine("امتیاز شما D یا کمتر است.");
}
// خروجی: امتیاز شما B است.
- بلوک
if
: اگر شرط داخل پرانتزtrue
باشد، کد داخل بلوکif
اجرا میشود. - بلوک
else if
: اگر شرطif
اولیهfalse
باشد، شرطelse if
بررسی میشود. میتوانید چندین بلوکelse if
داشته باشید. - بلوک
else
: اگر هیچ یک از شرایطif
یاelse if
درست نباشند، کد داخل بلوکelse
اجرا میشود (اختیاری).
2. دستور `switch`
دستور switch
برای بررسی یک متغیر در مقابل چندین مقدار ممکن استفاده میشود. این روش برای زمانی که تعداد زیادی if-else if
وجود دارد و همگی یک متغیر یکسان را بررسی میکنند، کد را خواناتر میکند.
char grade = 'B';
switch (grade)
{
case 'A':
Console.WriteLine("عالی!");
break; // break برای خروج از بلوک switch
case 'B':
Console.WriteLine("خیلی خوب!");
break;
case 'C':
Console.WriteLine("خوب.");
break;
case 'D':
case 'F': // میتوان چندین case را با هم گروهبندی کرد.
Console.WriteLine("نیاز به تلاش بیشتر.");
break;
default: // اگر هیچ یک از case ها مطابقت نداشته باشند
Console.WriteLine("نمره نامعتبر.");
break;
}
// خروجی: خیلی خوب!
case
: هرcase
یک مقدار ممکن برای متغیرswitch
را مشخص میکند.break
: ضروری است که پس از هر بلوکcase
ازbreak
استفاده کنید تا اجرای کد ازswitch
خارج شود. اگر ازbreak
استفاده نکنید، C# خطای کامپایل خواهد داد (به جز در مواردی که یکcase
خالی باشد و بهcase
بعدی برود).default
: اختیاری است و اگر هیچcase
دیگری مطابقت نداشته باشد، اجرا میشود.
3. عملگر شرطی (Ternary Operator)
یک شکل مختصر برای دستور if-else
که یک مقدار را بر اساس یک شرط باز میگرداند.
int age = 18;
string eligibility = (age >= 18) ? "واجد شرایط رای دادن" : "واجد شرایط رای دادن نیست";
Console.WriteLine(eligibility); // خروجی: واجد شرایط رای دادن
حلقهها (Loops)
حلقهها به شما امکان میدهند تا مجموعهای از دستورات را چندین بار، تا زمانی که یک شرط خاص برآورده شود، تکرار کنید.
1. حلقه `for`
حلقه for
برای تکرار یک تعداد مشخصی از دفعات استفاده میشود و شامل سه بخش اصلی است: مقداردهی اولیه، شرط، و عبارت تکرار.
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"تکرار شماره: {i}");
}
/* خروجی:
تکرار شماره: 0
تکرار شماره: 1
تکرار شماره: 2
تکرار شماره: 3
تکرار شماره: 4
*/
- مقداردهی اولیه (Initialization):
int i = 0;
- قبل از شروع حلقه یک بار اجرا میشود. - شرط (Condition):
i < 5;
- قبل از هر تکرار بررسی میشود. اگرtrue
باشد، حلقه ادامه مییابد. - عبارت تکرار (Iterator):
i++;
- پس از هر تکرار اجرا میشود (معمولاً برای افزایش/کاهش شمارنده).
2. حلقه `while`
حلقه while
تا زمانی که یک شرط خاص true
باشد، به اجرای دستورات ادامه میدهد. شرط قبل از هر تکرار بررسی میشود.
int count = 0;
while (count < 3)
{
Console.WriteLine($"شمارش: {count}");
count++;
}
/* خروجی:
شمارش: 0
شمارش: 1
شمارش: 2
*/
مهم است که مطمئن شوید شرط while
در نهایت false
میشود، وگرنه حلقه بینهایت (infinite loop) خواهید داشت.
3. حلقه `do-while`
حلقه do-while
شبیه به while
است، با این تفاوت که بلوک کد حداقل یک بار اجرا میشود، زیرا شرط در انتهای حلقه بررسی میشود.
int i = 0;
do
{
Console.WriteLine($"اجرا حداقل یک بار: {i}");
i++;
} while (i < 0); // شرط غلط است، اما حلقه یک بار اجرا میشود
// خروجی: اجرا حداقل یک بار: 0
4. حلقه `foreach`
حلقه foreach
برای پیمایش بر روی عناصر یک مجموعه (مانند آرایهها یا لیستها) طراحی شده است. این حلقه به طور خودکار عناصر را یکی یکی در اختیار شما قرار میدهد و نیازی به مدیریت اندیسها نیست.
string[] fruits = { "سیب", "پرتقال", "موز" };
foreach (string fruit in fruits)
{
Console.WriteLine($"میوه: {fruit}");
}
/* خروجی:
میوه: سیب
میوه: پرتقال
میوه: موز
*/
دستورات `break` و `continue`
break
: برای خروج فوری از حلقه (یا دستورswitch
) استفاده میشود.continue
: برای پرش از بقیه کد در تکرار فعلی حلقه و رفتن به تکرار بعدی استفاده میشود.
for (int i = 0; i < 10; i++)
{
if (i == 3)
{
continue; // پرش از تکرار 3
}
if (i == 7)
{
break; // خروج از حلقه
}
Console.WriteLine(i);
}
/* خروجی:
0
1
2
4
5
6
*/
با ترکیب دستورات شرطی و حلقهها، شما میتوانید منطق برنامه را به صورت پویا کنترل کرده و رفتارهای پیچیدهای را بر اساس دادههای ورودی یا وضعیت برنامه ایجاد کنید.
آشنایی با توابع و متدها در C#
در برنامهنویسی، توابع (Functions) یا متدها (Methods) بلوکهای کدی هستند که یک کار خاص را انجام میدهند. استفاده از توابع به شما امکان میدهد کد خود را سازماندهی کرده، قابلیت استفاده مجدد (reusability) آن را افزایش دهید و خوانایی و نگهداری برنامه را بهبود بخشید. در C#، توابع اغلب به عنوان "متد" (Method) شناخته میشوند، زیرا همیشه بخشی از یک کلاس یا struct هستند.
چرا از متدها استفاده کنیم؟
- قابلیت استفاده مجدد: یک متد را یک بار مینویسید و بارها در قسمتهای مختلف برنامه فراخوانی میکنید.
- سازماندهی کد: کد را به بخشهای کوچکتر و قابل مدیریت تقسیم میکند.
- خوانایی بهتر: نامهای معنادار برای متدها، هدف کد را واضحتر میکند.
- اشکالزدایی آسانتر: پیدا کردن و رفع خطاها در بلوکهای کوچکتر کد راحتتر است.
تعریف یک متد
سینتکس کلی برای تعریف یک متد در C# به صورت زیر است:
[سطح_دسترسی] [کلمه_کلیدی_اختیاری] نوع_بازگشتی نام_متد([پارامترها])
{
// بدنهی متد (دستوراتی که متد انجام میدهد)
// [return مقدار_بازگشتی;]
}
- سطح دسترسی (Access Modifier): (مانند
public
,private
,protected
) مشخص میکند که چه بخشهایی از برنامه میتوانند به این متد دسترسی داشته باشند.public
به معنی دسترسی از هر کجا است. - کلمه کلیدی اختیاری (Optional Modifier): (مانند
static
,abstract
,virtual
,override
) کلمه کلیدیstatic
به این معنی است که متد متعلق به کلاس است و نه به یک شیء از آن کلاس. متدMain
یک متدstatic
است. - نوع بازگشتی (Return Type): نوع دادهای که متد پس از اجرا برمیگرداند. اگر متد مقداری بر نمیگرداند، از کلمه کلیدی
void
استفاده میشود. - نام متد (Method Name): یک نام معنادار برای متد، بهتر است با حرف بزرگ شروع شود (PascalCase).
- پارامترها (Parameters): لیستی از متغیرها که متد برای انجام کار خود به آنها نیاز دارد. هر پارامتر شامل نوع داده و نام آن است، مانند
(int number, string message)
. اگر متد پارامتری نداشته باشد، پرانتزها خالی میمانند()
. - بدنهی متد (Method Body): کدی که داخل متد اجرا میشود، داخل آکولادها
{}
قرار میگیرد. - دستور
return
: اگر متد دارای نوع بازگشتی غیر ازvoid
باشد، باید با دستورreturn
یک مقدار از آن نوع برگرداند.
مثالهایی از متدها
1. متد بدون پارامتر و بدون مقدار بازگشتی (`void`)
public class Greeter
{
public void SayHello()
{
Console.WriteLine("سلام!");
}
}
// در متد Main یا جای دیگر:
Greeter greeter = new Greeter(); // ابتدا یک شیء از کلاس Greeter میسازیم
greeter.SayHello(); // فراخوانی متد
// خروجی: سلام!
اگر متد static
بود، نیازی به ساخت شیء نبود:
public class Utilities
{
public static void SayGoodbye()
{
Console.WriteLine("خداحافظ!");
}
}
// در متد Main یا جای دیگر:
Utilities.SayGoodbye(); // فراخوانی متد static به وسیله نام کلاس
// خروجی: خداحافظ!
2. متد با پارامتر و بدون مقدار بازگشتی (`void`)
public class Calculator
{
public void AddNumbers(int num1, int num2)
{
int sum = num1 + num2;
Console.WriteLine($"حاصل جمع: {sum}");
}
}
// در متد Main:
Calculator calc = new Calculator();
calc.AddNumbers(5, 10); // خروجی: حاصل جمع: 15
3. متد با پارامتر و با مقدار بازگشتی
public class AreaCalculator
{
public double CalculateCircleArea(double radius)
{
return Math.PI * radius * radius;
}
}
// در متد Main:
AreaCalculator areaCalc = new AreaCalculator();
double radius = 7.0;
double area = areaCalc.CalculateCircleArea(radius);
Console.WriteLine($"مساحت دایره با شعاع {radius} برابر است با: {area:F2}"); // F2 برای نمایش 2 رقم اعشار
// خروجی: مساحت دایره با شعاع 7 برابر است با: 153.94
پارامترها: پاس دادن با مقدار و با ارجاع (`ref`, `out`)
پاس دادن با مقدار (Pass by Value - پیشفرض)
هنگامی که پارامترها به صورت پیشفرض پاس داده میشوند، یک کپی از مقدار آنها به متد ارسال میشود. تغییرات در پارامتر داخل متد، بر روی متغیر اصلی خارج از متد تأثیری ندارد.
public void Increment(int number)
{
number++;
Console.WriteLine($"Inside method: {number}"); // 6
}
int myNum = 5;
Increment(myNum);
Console.WriteLine($"Outside method: {myNum}"); // 5 (بدون تغییر)
پاس دادن با ارجاع (Pass by Reference) - کلمات کلیدی `ref` و `out`
برای اینکه متد بتواند مقدار متغیر اصلی را تغییر دهد، باید آن را با ارجاع پاس داد. C# دو کلمه کلیدی برای این منظور ارائه میدهد: ref
و out
.
ref
: متغیری که باref
پاس داده میشود، باید قبل از فراخوانی متد مقداردهی اولیه شده باشد.out
: متغیری که باout
پاس داده میشود، نیازی به مقداردهی اولیه ندارد، اما متد فراخوانی شده *باید* قبل از اتمام، به آن مقدار اولیه دهد.
public void ModifyValueRef(ref int value)
{
value = value * 2;
}
public void GetCalculationResults(int num1, int num2, out int sum, out int product)
{
sum = num1 + num2;
product = num1 * num2;
}
// در متد Main:
int originalNum = 10;
ModifyValueRef(ref originalNum);
Console.WriteLine($"Modified originalNum: {originalNum}"); // 20
int totalSum;
int totalProduct;
GetCalculationResults(5, 8, out totalSum, out totalProduct);
Console.WriteLine($"Sum: {totalSum}, Product: {totalProduct}"); // Sum: 13, Product: 40
Overloading متد (Method Overloading)
به شما امکان میدهد چندین متد با یک نام یکسان در یک کلاس داشته باشید، به شرطی که لیست پارامترهای آنها (تعداد، نوع یا ترتیب پارامترها) متفاوت باشد. نوع بازگشتی نمیتواند تنها عامل تفاوت باشد.
public class Printer
{
public void Print(int number)
{
Console.WriteLine($"چاپ عدد: {number}");
}
public void Print(string text)
{
Console.WriteLine($"چاپ متن: {text}");
}
public void Print(double number, string unit)
{
Console.WriteLine($"چاپ مقدار: {number} {unit}");
}
}
// در متد Main:
Printer p = new Printer();
p.Print(123); // فراخوانی Print(int)
p.Print("C# is fun!"); // فراخوانی Print(string)
p.Print(99.5, "kg"); // فراخوانی Print(double, string)
با تسلط بر نحوه تعریف و استفاده از متدها، شما میتوانید کدهای خود را به قطعات منطقی و قابل استفاده مجدد تقسیم کنید که این یک گام مهم در برنامهنویسی حرفهای است.
نگاهی اجمالی به برنامهنویسی شیگرا (OOP) در C#
C# یک زبان برنامهنویسی کاملاً شیگرا (Object-Oriented Programming - OOP) است. OOP یک پارادایم برنامهنویسی است که بر مفهوم "اشیاء" تمرکز دارد که میتوانند دادهها (ویژگیها/properties) و کد (رفتارها/methods) را در خود نگه دارند. درک اصول OOP برای نوشتن کدهای C# تمیز، ماژولار و قابل نگهداری بسیار حیاتی است.
اصول چهارگانه OOP
OOP بر پایه چهار اصل اساسی استوار است:
1. کپسولهسازی (Encapsulation)
کپسولهسازی به معنی بستهبندی دادهها (ویژگیها) و متدهایی که بر روی آن دادهها عمل میکنند، در یک واحد منفرد (کلاس) و مخفی کردن جزئیات داخلی پیادهسازی از دنیای بیرون است. این کار از طریق استفاده از سطوح دسترسی (public
, private
, protected
) انجام میشود. به این ترتیب، فقط متدهای تعریف شده در کلاس میتوانند به دادههای داخلی دسترسی یا آنها را تغییر دهند، که این امر به حفاظت از یکپارچگی دادهها کمک میکند.
public class BankAccount
{
private decimal _balance; // فیلد خصوصی برای نگهداری موجودی
public BankAccount(decimal initialBalance)
{
_balance = initialBalance;
}
public void Deposit(decimal amount) // متد عمومی برای واریز
{
if (amount > 0)
{
_balance += amount;
Console.WriteLine($"واریز موفق. موجودی جدید: {_balance}");
}
}
public decimal GetBalance() // متد عمومی برای دریافت موجودی
{
return _balance;
}
}
// استفاده از کلاس BankAccount
BankAccount myAccount = new BankAccount(1000);
myAccount.Deposit(500); // استفاده از متد عمومی
// Console.WriteLine(myAccount._balance); // خطا: _balance خصوصی است و قابل دسترسی نیست.
Console.WriteLine($"موجودی فعلی: {myAccount.GetBalance()}");
در C#، اغلب از "Properties" برای دسترسی کنترلشده به فیلدهای خصوصی استفاده میشود که شامل یک "getter" (برای خواندن) و یک "setter" (برای نوشتن) هستند.
public class Person
{
public string Name { get; set; } // Auto-implemented property
public int Age { get; private set; } // Age فقط میتواند درون کلاس تنظیم شود
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
2. وراثت (Inheritance)
وراثت به کلاسها اجازه میدهد تا ویژگیها و متدهای خود را از کلاسهای دیگر (کلاس پایه/پدر) به ارث ببرند. این امر باعث افزایش قابلیت استفاده مجدد کد و ایجاد سلسله مراتب منطقی بین کلاسها میشود. یک کلاس مشتق شده (کلاس فرزند) میتواند ویژگیها و متدهای کلاس پایه را گسترش دهد یا تغییر دهد.
public class Animal // کلاس پایه
{
public string Name { get; set; }
public Animal(string name)
{
Name = name;
}
public void Eat()
{
Console.WriteLine($"{Name} در حال خوردن است.");
}
}
public class Dog : Animal // Dog از Animal ارث میبرد (با استفاده از علامت :)
{
public string Breed { get; set; }
public Dog(string name, string breed) : base(name) // فراخوانی سازنده کلاس پایه
{
Breed = breed;
}
public void Bark()
{
Console.WriteLine($"{Name} واق واق میکند.");
}
}
// استفاده از وراثت
Dog myDog = new Dog("Buddy", "Golden Retriever");
myDog.Eat(); // متد ارث برده شده از Animal
myDog.Bark(); // متد خاص Dog
3. چندریختی (Polymorphism)
چندریختی به معنی "اشکال بسیار" است و به شما امکان میدهد تا اشیاء از انواع مختلف را به یک شیوه واحد مدیریت کنید، در حالی که آنها رفتارهای متفاوتی را نشان میدهند. این اصل معمولاً از طریق متدهای virtual
و override
یا از طریق رابطها (Interfaces) پیادهسازی میشود.
public class Shape // کلاس پایه
{
public virtual void Draw() // متد مجازی که میتواند در کلاسهای فرزند override شود
{
Console.WriteLine("رسم یک شکل عمومی.");
}
}
public class Circle : Shape
{
public override void Draw() // override کردن متد Draw از کلاس پایه
{
Console.WriteLine("رسم یک دایره.");
}
}
public class Rectangle : Shape
{
public override void Draw()
{
Console.WriteLine("رسم یک مستطیل.");
}
}
// استفاده از چندریختی
Shape[] shapes = new Shape[3];
shapes[0] = new Shape();
shapes[1] = new Circle();
shapes[2] = new Rectangle();
foreach (Shape s in shapes)
{
s.Draw(); // هر شیء، متد Draw مخصوص به خود را فراخوانی میکند
}
/* خروجی:
رسم یک شکل عمومی.
رسم یک دایره.
رسم یک مستطیل.
*/
4. انتزاع (Abstraction)
انتزاع به معنی پنهان کردن جزئیات پیادهسازی و نمایش تنها اطلاعات ضروری به کاربر است. این کار را میتوان از طریق کلاسهای انتزاعی (Abstract Classes) و رابطها (Interfaces) انجام داد. کلاس انتزاعی میتواند شامل متدهای انتزاعی (بدون پیادهسازی) باشد که باید توسط کلاسهای مشتق شده پیادهسازی شوند.
public abstract class Vehicle // کلاس انتزاعی
{
public abstract void Drive(); // متد انتزاعی، بدون پیادهسازی در کلاس پایه
public void Stop() // متد غیر انتزاعی (با پیادهسازی)
{
Console.WriteLine("وسیله نقلیه متوقف شد.");
}
}
public class Car : Vehicle
{
public override void Drive() // پیادهسازی متد انتزاعی Drive
{
Console.WriteLine("ماشین در حال رانندگی است.");
}
}
// استفاده از انتزاع
// Vehicle myVehicle = new Vehicle(); // خطا: نمیتوان از کلاس انتزاعی نمونه ساخت
Car myCar = new Car();
myCar.Drive();
myCar.Stop();
کلاسها و اشیاء
در OOP، کلاس (Class) یک طرح اولیه یا الگو برای ایجاد اشیاء است. این یک تعریف از ویژگیها (دادهها) و رفتارها (متدها) است که اشیاء بر اساس آن خواهند داشت. شیء (Object) یک نمونه (instance) از یک کلاس است. وقتی کلاسی را تعریف میکنید، در واقع هنوز حافظهای برای آن تخصیص داده نشده است. زمانی که یک شیء از آن کلاس میسازید، حافظه برای آن تخصیص مییابد و میتوانید از ویژگیها و متدهای آن استفاده کنید.
// تعریف کلاس
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
// سازنده (Constructor): متد خاصی برای مقداردهی اولیه شیء هنگام ساخت آن
public Product(int id, string name, decimal price)
{
ProductId = id;
Name = name;
Price = price;
}
public void DisplayProductInfo()
{
Console.WriteLine($"ID: {ProductId}, Name: {Name}, Price: {Price:C}"); // C برای فرمت ارز
}
}
// ایجاد شیء (نمونهسازی)
Product laptop = new Product(101, "لپ تاپ HP", 1200.50m); // ایجاد یک شیء از کلاس Product
Product mouse = new Product(102, "موس بیسیم", 25.99m);
// استفاده از اشیاء
laptop.DisplayProductInfo();
mouse.DisplayProductInfo();
OOP یک مفهوم گسترده است و درک عمیق آن نیازمند زمان و تجربه است. با این حال، آشنایی با این اصول بنیادی، شما را در مسیر صحیح نوشتن کدهای ساختاریافته و قابل توسعه در C# قرار میدهد.
کار با آرایهها و کالکشنها در C#
برای ذخیره و مدیریت مجموعهای از دادهها، C# دو مفهوم اصلی را ارائه میدهد: آرایهها (Arrays) و کالکشنها (Collections). در حالی که آرایهها ساختارهای دادهای ایستا با اندازهای ثابت هستند، کالکشنها راهحلهای پویا و انعطافپذیرتری را ارائه میدهند که از فضای نام System.Collections.Generic
میآیند.
آرایهها (Arrays)
آرایه مجموعهای از عناصر همنوع است که در خانههای متوالی حافظه ذخیره میشوند. اندازه آرایه پس از تعریف قابل تغییر نیست. عناصر آرایه با استفاده از یک اندیس (index) عددی که از صفر شروع میشود، قابل دسترسی هستند.
تعریف و مقداردهی اولیه آرایه
// 1. تعریف و مقداردهی با اندازه مشخص، عناصر به مقدار پیشفرض خود مقداردهی میشوند (مثلاً 0 برای int)
int[] numbers = new int[5]; // یک آرایه از 5 عدد صحیح (ایندکسها: 0, 1, 2, 3, 4)
// 2. مقداردهی اولیه عناصر
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
// ...
// 3. تعریف و مقداردهی اولیه همزمان با مقادیر
string[] names = new string[] { "علی", "سارا", "رضا", "مریم" };
// 4. تعریف و مقداردهی اولیه کوتاه شده (کامپایلر نوع و اندازه را استنتاج میکند)
double[] prices = { 19.99, 5.50, 75.20 };
// 5. آرایه با var (همانند حالت 4)
var products = new[] { "لپ تاپ", "کیبورد", "موس" }; // نوع string[] استنتاج میشود
دسترسی به عناصر آرایه
برای دسترسی به عناصر آرایه از اندیس آنها استفاده میشود:
Console.WriteLine(names[0]); // خروجی: علی
Console.WriteLine(prices[2]); // خروجی: 75.20
// تغییر مقدار یک عنصر
numbers[0] = 100;
Console.WriteLine(numbers[0]); // خروجی: 100
دسترسی به اندیسی خارج از محدوده آرایه (مثلاً `names[4]` در مثال بالا) باعث خطای زمان اجرا (`IndexOutOfRangeException`) میشود.
طول آرایه
ویژگی Length
طول (تعداد عناصر) آرایه را برمیگرداند:
Console.WriteLine($"تعداد نامها: {names.Length}"); // خروجی: 4
پیمایش آرایه
میتوانید با حلقههای for
یا foreach
روی عناصر آرایه پیمایش کنید:
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"نام در اندیس {i}: {names[i]}");
}
foreach (string name in names)
{
Console.WriteLine($"نام: {name}");
}
آرایههای چندبعدی (Multidimensional Arrays)
میتوانید آرایههایی با بیش از یک بعد (مثلاً ماتریسها) تعریف کنید:
// آرایه دوبعدی (ماتریس 2x3)
int[,] matrix = new int[2, 3] {
{1, 2, 3},
{4, 5, 6}
};
Console.WriteLine(matrix[0, 1]); // خروجی: 2 (عنصر در سطر 0، ستون 1)
// آرایه دندانهدار (Jagged Array) - آرایهای از آرایهها
int[][] jaggedArray = new int[3][]; // 3 سطر
jaggedArray[0] = new int[] { 1, 2, 3 };
jaggedArray[1] = new int[] { 4, 5 };
jaggedArray[2] = new int[] { 6, 7, 8, 9 };
Console.WriteLine(jaggedArray[1][0]); // خروجی: 4
کالکشنها (Collections)
کالکشنها، به خصوص Generic Collections در فضای نام System.Collections.Generic
، راهحلهای انعطافپذیرتری برای ذخیره و مدیریت گروههایی از اشیاء ارائه میدهند. آنها برخلاف آرایهها، پویا هستند (اندازه آنها میتواند در زمان اجرا تغییر کند) و معمولاً انواع ایمن (type-safe) هستند.
1. `List`
List
یک لیست پویا و نوع ایمن است که میتواند تعداد متغیری از عناصر از نوع T
را نگهداری کند. T
(T for Type) به معنی یک نوع داده عمومی (generic) است که شما هنگام تعریف لیست مشخص میکنید.
using System.Collections.Generic; // لازم برای استفاده از List
List<string> cities = new List<string>(); // ایجاد یک لیست خالی از رشتهها
cities.Add("تهران");
cities.Add("اصفهان");
cities.Add("شیراز");
// افزودن چندین عنصر همزمان
cities.AddRange(new string[] { "مشهد", "تبریز" });
Console.WriteLine($"تعداد شهرها: {cities.Count}"); // خروجی: 5
// دسترسی به عناصر (مانند آرایه با اندیس)
Console.WriteLine(cities[0]); // خروجی: تهران
// حذف یک عنصر
cities.Remove("اصفهان");
cities.RemoveAt(0); // حذف عنصر در اندیس 0 (تهران)
// پیمایش
foreach (string city in cities)
{
Console.WriteLine($"شهر: {city}");
}
// بررسی وجود یک عنصر
if (cities.Contains("شیراز"))
{
Console.WriteLine("شیراز در لیست است.");
}
2. `Dictionary`
Dictionary
مجموعهای از جفتهای کلید-مقدار (key-value pairs) است. هر کلید باید منحصربهفرد باشد و برای بازیابی سریع مقدار مرتبط با آن استفاده میشود.
using System.Collections.Generic;
Dictionary<string, string> capitals = new Dictionary<string, string>();
capitals.Add("ایران", "تهران");
capitals.Add("فرانسه", "پاریس");
capitals.Add("آلمان", "برلین");
// دسترسی به مقدار با استفاده از کلید
Console.WriteLine($"پایتخت فرانسه: {capitals["فرانسه"]}"); // خروجی: پاریس
// تغییر مقدار
capitals["آلمان"] = "برلین جدید";
// بررسی وجود کلید یا مقدار
if (capitals.ContainsKey("ایران"))
{
Console.WriteLine("ایران در دیکشنری است.");
}
// تلاش برای دریافت مقدار (بدون خطا در صورت عدم وجود کلید)
if (capitals.TryGetValue("ژاپن", out string japanCapital))
{
Console.WriteLine($"پایتخت ژاپن: {japanCapital}");
}
else
{
Console.WriteLine("ژاپن در دیکشنری نیست.");
}
// پیمایش
foreach (KeyValuePair<string, string> entry in capitals)
{
Console.WriteLine($"کشور: {entry.Key}, پایتخت: {entry.Value}");
}
// یا میتوانید فقط روی کلیدها یا مقادیر پیمایش کنید
foreach (string country in capitals.Keys) { /* ... */ }
foreach (string capital in capitals.Values) { /* ... */ }
3. `HashSet`
HashSet
مجموعهای از عناصر منحصربهفرد است که ترتیب خاصی ندارند. این کالکشن برای عملیات مجموعهای مانند اجتماع، اشتراک و تفاوت بسیار بهینه است.
using System.Collections.Generic;
HashSet<int> uniqueNumbers = new HashSet<int>();
uniqueNumbers.Add(1);
uniqueNumbers.Add(2);
uniqueNumbers.Add(1); // این اضافه نمیشود زیرا 1 از قبل وجود دارد
uniqueNumbers.Add(3);
Console.WriteLine($"تعداد عناصر: {uniqueNumbers.Count}"); // خروجی: 3 (1, 2, 3)
foreach (int num in uniqueNumbers)
{
Console.WriteLine(num);
}
4. `Queue` و `Stack`
Queue
(صف): ساختار دادهای FIFO (First-In, First-Out). عنصری که اول اضافه میشود، اول حذف میشود.Stack
(پشته): ساختار دادهای LIFO (Last-In, First-Out). عنصری که آخر اضافه میشود، اول حذف میشود.
// Queue
Queue<string> tasks = new Queue<string>();
tasks.Enqueue("Task 1"); // اضافه کردن
tasks.Enqueue("Task 2");
Console.WriteLine(tasks.Dequeue()); // حذف و بازگرداندن: Task 1
Console.WriteLine(tasks.Peek()); // مشاهده بدون حذف: Task 2
// Stack
Stack<int> history = new Stack<int>();
history.Push(10); // اضافه کردن
history.Push(20);
Console.WriteLine(history.Pop()); // حذف و بازگرداندن: 20
Console.WriteLine(history.Peek()); // مشاهده بدون حذف: 10
انتخاب بین آرایهها و کالکشنها به نیازهای خاص برنامه شما بستگی دارد. برای مجموعههای با اندازه ثابت و دسترسی سریع به اندیس، آرایهها مناسبند. اما برای انعطافپذیری، تغییر اندازه پویا و قابلیتهای پیشرفتهتر، کالکشنها گزینههای بهتری هستند.
مدیریت خطاها و استثناها در C#
در هر برنامهای، احتمال وقوع خطاها و شرایط غیرمنتظره وجود دارد. این خطاها میتوانند ناشی از ورودی نامعتبر کاربر، مشکلات شبکه، کمبود حافظه، یا تلاش برای دسترسی به فایلهای غیرموجود باشند. در C#، این شرایط غیرعادی به عنوان "استثنا" (Exception) شناخته میشوند. مدیریت صحیح استثناها برای ساخت برنامههای پایدار، قابل اعتماد و کاربرپسند بسیار حیاتی است.
استثنا چیست؟
یک استثنا، رویدادی است که در زمان اجرای برنامه رخ میدهد و جریان عادی اجرای برنامه را مختل میکند. زمانی که یک استثنا رخ میدهد و مدیریت نشود (unhandled exception)، برنامه معمولاً با خطا متوقف میشود (crash میکند).
مثالهایی از استثناهای رایج:
DivideByZeroException
: تلاش برای تقسیم بر صفر.NullReferenceException
: تلاش برای دسترسی به یک متغیر که مقدارnull
دارد.FormatException
: تبدیل یک رشته به یک نوع عددی نامعتبر.IndexOutOfRangeException
: دسترسی به عنصری در آرایه یا لیست با اندیسی خارج از محدوده.FileNotFoundException
: تلاش برای دسترسی به فایلی که وجود ندارد.
بلوک `try-catch-finally`
برای مدیریت استثناها در C#، از ساختار try-catch-finally
استفاده میشود. این ساختار به شما امکان میدهد کدی را که ممکن است استثنا ایجاد کند، در یک بلوک try
قرار دهید و سپس واکنش مناسبی به هر استثنای رخ داده نشان دهید.
try
{
// کدی که ممکن است باعث ایجاد استثنا شود
Console.Write("یک عدد وارد کنید: ");
string input = Console.ReadLine();
int number = int.Parse(input); // ممکن است FormatException رخ دهد
Console.Write("یک عدد دیگر برای تقسیم وارد کنید: ");
string divisorInput = Console.ReadLine();
int divisor = int.Parse(divisorInput); // ممکن است FormatException رخ دهد
int result = number / divisor; // ممکن است DivideByZeroException رخ دهد
Console.WriteLine($"نتیجه تقسیم: {result}");
}
catch (FormatException ex)
{
// این بلوک زمانی اجرا میشود که FormatException رخ دهد
Console.WriteLine("خطا: ورودی نامعتبر. لطفاً یک عدد وارد کنید.");
Console.WriteLine($"جزئیات خطا: {ex.Message}");
}
catch (DivideByZeroException ex)
{
// این بلوک زمانی اجرا میشود که DivideByZeroException رخ دهد
Console.WriteLine("خطا: نمیتوان بر صفر تقسیم کرد.");
Console.WriteLine($"جزئیات خطا: {ex.Message}");
}
catch (Exception ex) // یک بلوک catch عمومی برای گرفتن هر نوع استثنای دیگر
{
Console.WriteLine("یک خطای ناشناخته رخ داده است.");
Console.WriteLine($"جزئیات خطا: {ex.Message}");
// در محیطهای واقعی، اینجا باید خطا را لاگ کرد و شاید به کاربر یک پیام عمومیتر نشان داد.
}
finally
{
// این بلوک همیشه اجرا میشود، چه استثنایی رخ دهد و چه رخ ندهد.
// معمولاً برای آزادسازی منابع (مانند بستن فایلها یا اتصالات پایگاه داده) استفاده میشود.
Console.WriteLine("عملیات بررسی تقسیم به پایان رسید.");
}
اجزاء `try-catch-finally`
- `try` بلوک: کدی که انتظار دارید ممکن است استثنا ایجاد کند، در این بلوک قرار میگیرد.
- `catch` بلوک: پس از بلوک
try
میآید. اگر استثنایی در بلوکtry
رخ دهد، کنترل به بلوکcatch
مناسب منتقل میشود. شما میتوانید چندین بلوکcatch
برای انواع مختلف استثناها داشته باشید. بلوکهایcatch
از نوع خاصتر به نوع عمومیتر مرتب میشوند.Exception ex
:Exception
کلاس پایه تمام استثناها در C# است. استفاده ازcatch (Exception ex)
تمام استثناها را میگیرد، اما بهتر است تا حد امکان استثناهای خاص را بگیرید تا بتوانید واکنش دقیقتری نشان دهید.ex.Message
: یک ویژگی در شیء استثنا است که یک پیام متنی توصیفی از خطا را ارائه میدهد.ex.StackTrace
: اطلاعات مربوط به محل دقیق خطا در کد را ارائه میدهد که برای اشکالزدایی بسیار مفید است.
- `finally` بلوک: این بلوک اختیاری است و پس از اجرای بلوک
try
و تمام بلوکهایcatch
(در صورت وجود) اجرا میشود. این بلوک همیشه اجرا میشود، چه استثنایی رخ دهد، چه رخ ندهد، و چه حتی از بلوکtry
یاcatch
خارج شوید (مثلاً باreturn
). از آن برای پاکسازی منابع استفاده میشود.
پرتاب کردن استثنا (`throw`)
شما میتوانید به صورت دستی استثنا ایجاد کرده و پرتاب کنید (throw) تا یک وضعیت خطا را در برنامه خود گزارش دهید. این کار زمانی مفید است که یک متد یک وضعیت نامعتبر را تشخیص میدهد که نمیتواند آن را مدیریت کند و میخواهد به متد فراخواننده اطلاع دهد.
public int CalculateFactorial(int n)
{
if (n < 0)
{
// ایجاد و پرتاب یک استثنای ArgumentOutOfRangeException
throw new ArgumentOutOfRangeException(nameof(n), "فاکتوریل برای اعداد منفی تعریف نشده است.");
}
if (n == 0) return 1;
int result = 1;
for (int i = 1; i <= n; i++)
{
result *= i;
}
return result;
}
// در متد Main یا جای دیگر
try
{
int factorialResult = CalculateFactorial(-5);
Console.WriteLine($"فاکتوریل: {factorialResult}");
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine($"خطا در محاسبه فاکتوریل: {ex.Message}");
}
// خروجی: خطا در محاسبه فاکتوریل: فاکتوریل برای اعداد منفی تعریف نشده است.
`using` Statement برای منابع قابل دفع (`IDisposable`)
بسیاری از منابع (مانند فایلها، اتصالات پایگاه داده، جریانهای شبکه) باید پس از استفاده به درستی بسته و آزاد شوند تا از نشت حافظه یا سایر مشکلات جلوگیری شود. C# برای این منظور رابط IDisposable
و دستور using
را فراهم میکند. اشیائی که IDisposable
را پیادهسازی میکنند، میتوانند در یک بلوک using
استفاده شوند، که تضمین میکند متد Dispose()
آنها حتی در صورت بروز استثنا، فراخوانی میشود.
using System.IO;
// استفاده از using statement برای مدیریت خودکار منابع (در اینجا StreamWriter)
try
{
using (StreamWriter writer = new StreamWriter("log.txt"))
{
writer.WriteLine("این یک پیام لاگ است.");
writer.WriteLine("پیام دوم.");
// writer.Dispose() به طور خودکار در پایان بلوک using فراخوانی میشود
}
Console.WriteLine("فایل log.txt با موفقیت نوشته شد.");
}
catch (IOException ex)
{
Console.WriteLine($"خطا در نوشتن فایل: {ex.Message}");
}
مدیریت صحیح استثناها یک مهارت کلیدی در برنامهنویسی حرفهای است. با استفاده از try-catch-finally
و پرتاب استثناهای مناسب، میتوانید برنامههایی بسازید که نه تنها وظایف خود را انجام میدهند، بلکه در برابر خطاهای پیشبینی نشده نیز مقاوم هستند.
قدمهای بعدی: مسیر یادگیری C#
تبریک میگویم! شما با مفاهیم بنیادی C#، از نصب محیط توسعه و نوشتن اولین برنامه خود گرفته تا درک متغیرها، انواع داده، جریان کنترل، متدها، اصول شیگرایی و مدیریت استثناها، آشنا شدهاید. این دانش، سنگ بنای محکمی برای ادامه مسیر شما در دنیای برنامهنویسی C# است. اما یادگیری برنامهنویسی یک فرآیند مداوم است و برای تبدیل شدن به یک توسعهدهنده ماهر C#، باید مسیر یادگیری خود را ادامه دهید.
در اینجا چند پیشنهاد برای گامهای بعدی و زمینههایی که میتوانید در آنها عمیقتر شوید آورده شده است:
1. ساختارهای داده و الگوریتمها
اگرچه به کالکشنها پرداختیم، اما درک عمیقتر ساختارهای داده (مانند لینکدلیستها، درختها، گرافها) و الگوریتمهای رایج (مانند مرتبسازی، جستجو) برای حل مسائل پیچیدهتر و نوشتن کدهای کارآمد ضروری است. این دانش مستقل از زبان برنامهنویسی است، اما پیادهسازی آنها در C# به شما کمک میکند تا زبان را بهتر درک کنید.
2. برنامهنویسی ناهمگام (Asynchronous Programming)
در برنامههای مدرن، به خصوص در توسعه وب و برنامههای کاربردی با رابط کاربری گرافیکی، نیاز به انجام عملیاتهای طولانی مدت بدون مسدود کردن رابط کاربری یا نخ اصلی برنامه وجود دارد. C# با استفاده از کلمات کلیدی async
و await
، برنامهنویسی ناهمگام را بسیار آسان کرده است. این یک مفهوم حیاتی برای برنامههای پاسخگو و کارآمد است.
public async Task<string> DownloadContentAsync(string url)
{
using (HttpClient client = new HttpClient())
{
// await تا زمانی که عملیات I/O (دانلود) کامل شود، متد را مسدود نمیکند
// و کنترل را به فراخواننده برمیگرداند
string content = await client.GetStringAsync(url);
return content;
}
}
// نحوه فراخوانی
// string data = await DownloadContentAsync("http://example.com");
3. LINQ (Language Integrated Query)
LINQ (Language Integrated Query) یک ویژگی قدرتمند در C# است که به شما امکان میدهد با استفاده از سینتکس SQL-مانند، کوئریها را مستقیماً در کد C# خود برای مجموعههای داده (مانند لیستها، آرایهها، پایگاههای داده، XML) بنویسید. این کار کد را بسیار خواناتر و کارآمدتر میکند.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// استفاده از LINQ برای فیلتر و انتخاب
var evenNumbers = from num in numbers
where num % 2 == 0
select num;
foreach (var num in evenNumbers)
{
Console.WriteLine(num);
}
// خروجی: 2, 4, 6, 8, 10
4. توسعه وب با ASP.NET Core
اگر به توسعه وب علاقه دارید، ASP.NET Core یک فریمورک قدرتمند، کراسپلتفرم و با کارایی بالا برای ساخت وبسایتها، وبسرویسها (APIs) و برنامههای وب تکصفحهای (SPAs) است. مفاهیمی مانند MVC (Model-View-Controller) یا Razor Pages، API Development و Entity Framework Core (برای کار با پایگاه داده) را خواهید آموخت.
5. توسعه دسکتاپ
- WPF (Windows Presentation Foundation): برای ساخت برنامههای دسکتاپ ویندوز با رابط کاربری غنی و گرافیک قدرتمند.
- WinForms (Windows Forms): قدیمیتر اما همچنان برای برنامههای کاربردی سادهتر دسکتاپ مناسب است.
- MAUI (.NET Multi-platform App UI): جانشین Xamarin، برای ساخت برنامههای کراسپلتفرم بومی (iOS, Android, Windows, macOS) از یک پایگاه کد واحد.
6. توسعه بازی با Unity
اگر به بازیسازی علاقه دارید، Unity یکی از محبوبترین موتورهای بازیسازی است که از C# به عنوان زبان اصلی اسکریپتنویسی استفاده میکند. این حوزه نیازمند درک مفاهیم برنامهنویسی بازی، فیزیک، گرافیک و مدیریت منابع است.
7. الگوهای طراحی (Design Patterns)
الگوهای طراحی، راهحلهای عمومی و قابل استفاده مجدد برای مسائل رایج در طراحی نرمافزار هستند. یادگیری الگوهایی مانند Singleton, Factory, Observer و Strategy به شما کمک میکند تا کدهای ماژولارتر، قابل نگهداریتر و قابل توسعهتر بنویسید.
8. تست نویسی (Unit Testing)
نوشتن تستهای واحد برای کدهای شما، کیفیت نرمافزار را تضمین میکند و از بروز رگرسیونها (بازگشت خطاها) در آینده جلوگیری میکند. ابزارهایی مانند xUnit یا NUnit به همراه Visual Studio، این فرآیند را تسهیل میکنند.
9. SQL و دیتابیسها
تقریباً تمام برنامههای کاربردی نیاز به ذخیره و بازیابی دادهها دارند. یادگیری SQL (Structured Query Language) و نحوه تعامل C# با پایگاههای داده رابطهای (مانند SQL Server, PostgreSQL, MySQL) از طریق ORM ها (مانند Entity Framework Core) یا ADO.NET بسیار مهم است.
10. کار با Git و کنترل نسخه (Version Control)
Git یک سیستم کنترل نسخه توزیع شده است که برای ردیابی تغییرات کد و همکاری تیمی ضروری است. یادگیری Git و پلتفرمهایی مانند GitHub یا Azure DevOps برای هر توسعهدهندهای واجب است.
مهمتر از همه: تمرین کنید!
هیچ چیز جای تمرین عملی را نمیگیرد. سعی کنید پروژههای کوچک خودتان را بسازید. این میتواند یک برنامه مدیریت لیست وظایف، یک ماشین حساب پیچیدهتر، یک بازی ساده یا یک وبسایت کوچک باشد. در فرآیند ساخت، با چالشهای واقعی روبرو میشوید و مهارتهای حل مسئله خود را تقویت میکنید.
مسیر یادگیری C# هیجانانگیز و پر از فرصت است. با پایداری، تمرین مداوم و کنجکاوی، شما میتوانید به یک توسعهدهنده C# ماهر تبدیل شوید و پروژههای چشمگیری را خلق کنید. موفق باشید!
“تسلط به برنامهنویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT”
"تسلط به برنامهنویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT"
"با شرکت در این دوره جامع و کاربردی، به راحتی مهارتهای برنامهنویسی پایتون را از سطح مبتدی تا پیشرفته با کمک هوش مصنوعی ChatGPT بیاموزید. این دوره، با بیش از 6 ساعت محتوای آموزشی، شما را قادر میسازد تا به سرعت الگوریتمهای پیچیده را درک کرده و اپلیکیشنهای هوشمند ایجاد کنید. مناسب برای تمامی سطوح با زیرنویس فارسی حرفهای و امکان دانلود و تماشای آنلاین."
ویژگیهای کلیدی:
بدون نیاز به تجربه قبلی برنامهنویسی
زیرنویس فارسی با ترجمه حرفهای
۳۰ ٪ تخفیف ویژه برای دانشجویان و دانش آموزان