ساختار کلی برنامه های C#

ساختار کلی برنامه‌های #C

وقتی یک پروژه‌ی کنسول اپلیکیشن جدید می‌سازید، ممکن است با دو شکل متفاوت از کد اولیه روبه‌رو شوید. در این مقاله ابتدا شکل سنتی را بررسی می‌کنیم، سپس به قالب‌های جدیدتر مثل Top-Level Statements می‌پردازیم.

۱. کد سنتی

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            int age = 29;
            Console.WriteLine($"AGE: {age}");
        }
    }
}

این کد از چند بخش تشکیل شده که با هم مرور می‌کنیم:

using System

برای استفاده از کلاس‌های متداول در سی‌شارپ (مانند Console) باید فضای نام (namespace) مربوطه، یعنی System را وارد کنیم.
دقت کنید که System یک فضای نام است، نه کلاس. این کار با دستور using در ابتدای فایل انجام می‌شود.

namespace MyFirstApp

فضای نام (namespace) راهی برای گروه‌بندی کلاس‌ها و جلوگیری از تداخل نام‌هاست (مثل پوشه‌بندی فایل‌ها).
این قسمت نام فضایی را مشخص می‌کند که کلاس‌های درون آن قابل شناسایی هستند. اگر دو برنامه‌نویس کلاسی با نام یکسان (مثلاً Customer) بسازند، با قرار دادن در namespaceهای متفاوت، از یکدیگر تفکیک می‌شوند.

class Program

کلاس اصلی پروژه است که نقطه‌ی شروع برنامه در آن قرار دارد. کامپایلر سی‌شارپ برای اجرای برنامه به دنبال یک کلاس با متد Main می‌گردد.

static void Main(string[] args)

دقیقاً نقطه‌ی شروع برنامه است. هر برنامه‌ی سی‌شارپ باید یک نقطه‌ی ورود داشته باشد که به‌طور پیش‌فرض همین متد است.

  • static: متد به خود کلاس تعلق دارد، نه به یک نمونه (instance) از آن. بنابراین زمان اجرا بدون نیاز به new فراخوانی می‌شود.

  • void یا int: نوع خروجی. void یعنی مقدار بازگشتی ندارد. اگر نیاز باشد کد وضعیت به سیستم‌عامل برگردانید، می‌توان از int استفاده کرد (مثلاً return 0;).

  • string[] args: آرایه‌ای از آرگومان‌های خط فرمان. اگر برنامه را از خط فرمان با پارامتر اجرا کنید (مثلاً myapp.exe -n 10)، این آرگومان‌ها در این آرایه قرار می‌گیرند.

بدنه متد Main

دستوراتی که درون این متد نوشته می‌شوند، هنگام اجرای برنامه به ترتیب اجرا خواهند شد.

۲. فضای نام (Namespace) به‌تفصیل

برای استفاده از یک کلاس که در namespace دیگری قرار دارد، دو راه دارید:

  1. نام کامل (Fully Qualified Name): مسیر کامل فضای نام تا کلاس را بنویسید:
    System.Console.WriteLine("...");

  2. دستور using در ابتدای فایل: فضای نام را وارد کنید تا بتوانید مستقیماً از نام کلاس استفاده کنید:
    using System;
    سپس Console.WriteLine("...");

۳. انواع دیگر using

علاوه بر using معمولی، سه شکل دیگر هم وجود دارد:

  • using static: امکان دسترسی مستقیم به اعضای استاتیک یک کلاس را فراهم می‌کند.
    مثال: using static System.Math; → سپس می‌توانید به‌جای Math.Sqrt(...) فقط Sqrt(...) بنویسید.

  • using alias: برای تعریف نام مستعار برای یک نوع (type) به‌کار می‌رود.
    مثال: using MyConsole = System.Console; → می‌توانید MyConsole.WriteLine("..."); استفاده کنید.

  • global using: اگر با پیشوند global در یک فایل تعریف شود (معمولاً فایل GlobalUsings.cs یا Usings.cs)، در تمام فایل‌های پروژه اعمال می‌شود.
    از C# 10 و NET 6. به بعد، قالب‌های جدید پروژه (مثل Console App) به‌صورت خودکار یک مجموعه global using پیش‌فرض دارند که فضای نام‌های پرکاربردی مثل System، System.Collections.Generic و System.Linq را شامل می‌شود. به همین دلیل در بسیاری از پروژه‌های جدید نیازی به نوشتن using System; نیست.

۴. Top-Level Statements (از C# 9 به بعد)

برای برنامه‌های ساده می‌توان کد را بدون نوشتن namespace، کلاس و متد Main نوشت. این سبک کدنویسی را Top-Level Statements می‌نامند.

Console.WriteLine("Hello from top-level!");
Console.WriteLine("Args: " + string.Join(", ", args));

در پشت صحنه، کامپایلر این کد را به یک کلاس و متد Main سنتی تبدیل می‌کند. آرایه‌ی args نیز به‌طور خودکار در دسترس است.

نکات مهم درباره Top-Level Statements

  • هر پروژه فقط می‌تواند یک فایل دارای Top-Level Statements داشته باشد.

  • نمی‌توانید یک namespace جدید در همان فایل تعریف کنید، زیرا فضای نام فایل از قبل مشخص است (معمولاً global namespace). اما می‌توانید انواع دیگر (class, struct, record و …) را پس از دستورات Top-Level تعریف کنید؛ با این تفاوت که این انواع، به‌عنوان انواع تودرتو (nested) درون کلاس تولیدشده‌ی خودکار قرار می‌گیرند.

  • این سبک برای برنامه‌های خیلی کوچک، اسکریپتی، آموزشی و ابزارهای سریع عالی است.

  • در برنامه‌های بزرگ و ASP.NET Core معمولاً از قالب سنتی یا Minimal API استفاده می‌شود که ترکیبی از این دو است.

اگر در پروژه‌تان global using System; وجود داشته باشد (که در قالب‌های جدید هست)، حتی می‌توانید using System را هم حذف کنید و بنویسید:

// global using System در پروژه فعال است
Console.WriteLine("Hello, World!");

 

۵. کامنت‌ها و مستندسازی

کامنت تک‌خطی

// این یک کامنت است
int age = 25;

کامنت چندخطی

/*
این یک کامنت
چند خطی است
*/
Console.WriteLine("Done");

(علامت کامنت چندخطی */ و /* است؛ نه *//* که اشتباه رایجی است.)

کامنت مستندسازی XML

اگر قبل از تعریف کلاس، متد، پراپرتی یا اینترفیس سه اسلش /// تایپ کنید، ویژوال استودیو یک قالب XML آماده تولید می‌کند که می‌توانید توضیحات را درون تگ‌های آن پر کنید.

قالب تولیدشده شبیه این است:

/// <summary>
/// 
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>

و پس از تکمیل به این شکل درمی‌آید:

/// <summary>
/// محاسبه‌ی مجموع دو عدد صحیح
/// </summary>
/// <param name="a">عدد اول</param>
/// <param name="b">عدد دوم</param>
/// <returns>مجموع a و b</returns>
static int Add(int a, int b)
{
    return a + b;
}

این مستندات هم به خوانایی کد کمک می‌کند و هم می‌توان از آن‌ها برای تولید خودکار مستندات فنی استفاده کرد.


جمع‌بندی

  • namespace ابزاری برای نظم‌دهی و جلوگیری از تداخل نام‌هاست.

  • متد Main نقطه‌ی شروع اجباری برنامه در سبک سنتی است.

  • دستور using راهی برای ساده‌سازی دسترسی به کلاس‌های namespaceهای دیگر است.

  • global using و implicit usings کارهای تکراری را کاهش می‌دهند.

  • Top-Level Statements گزینه‌ای برای نوشتن سریع‌تر برنامه‌های کوچک، بدون مراسم تکراری کلاس و متد Main است.

  • کامنت‌ها و مستندات XML کد را خواناتر و قابل‌نگهداری‌تر می‌کنند.

شایان حسین پوریان