مقدمه

متدها (Methods) یکی از اساسی‌ترین واحدهای سازنده در هر برنامه C# هستند. یک متد، بلوکی از کد است که یک وظیفه‌ی مشخص را انجام می‌دهد و می‌توان آن را بارها و بارها از نقاط مختلف برنامه فراخوانی کرد. استفاده از متدها به ما کمک می‌کند تا کدهای خود را سازماندهی کنیم، از تکرار کد (بر اساس اصل DRY - Don't Repeat Yourself) جلوگیری کرده و برنامه‌هایی خواناتر و با قابلیت نگهداری بالاتر بنویسیم. در درس‌های گذشته ما به طور مداوم از متدها استفاده کرده‌ایم، مانند متد Console.WriteLine(). در این درس، به طور کامل با نحوه‌ی تعریف، فراخوانی و ویژگی‌های پیشرفته‌تر متدها در C# آشنا خواهیم شد.

تعریف و فراخوانی یک متد

یک متد از دو بخش اصلی تشکیل شده است: امضای متد (Method Signature) و بدنه‌ی متد (Method Body). امضای متد، اطلاعات کلی متد را مشخص می‌کند و بدنه‌ی آن، شامل دستوراتی است که باید اجرا شوند.

اجزای یک متد

امضای یک متد شامل موارد زیر است:

  • سطح دسترسی (Access Modifier): مشخص می‌کند که متد از کجا قابل دسترسی است (مثلاً public یا private). این موضوع در فصل‌های آینده به تفصیل بررسی می‌شود.
  • مقدار بازگشتی (Return Type): نوع داده‌ای که متد پس از اتمام کار خود برمی‌گرداند. اگر متد مقداری را برنگرداند، از کلمه‌ی کلیدی void استفاده می‌شود.
  • نام متد (Method Name): یک نام توصیفی برای متد.
  • پارامترها (Parameters): لیستی از متغیرها که به عنوان ورودی به متد داده می‌شوند. این بخش اختیاری است.
Copy Icon Program.cs
// A simple method with no parameters and no return value
void SayHello()
{
    Console.WriteLine("Hello, World!");
}

// A method with two parameters that returns a value
int Add(int a, int b)
{
    int sum = a + b;
    return sum;
}

// --- Calling the methods ---

// Calling a method is also known as invoking it
SayHello(); // Output: Hello, World!

// Calling the Add method and storing the result
int result = Add(5, 3);
Console.WriteLine(result); // Output: 8

در کد بالا، ابتدا دو متد SayHello و Add تعریف شده‌اند. متد SayHello هیچ ورودی (پارامتر) ندارد و هیچ خروجی هم برنمی‌گرداند (مقدار بازگشتی آن void است). متد Add دو پارامتر از نوع int دریافت کرده و حاصل جمع آن‌ها را که یک int است، با استفاده از کلمه‌ی کلیدی return برمی‌گرداند. سپس در ادامه، این دو متد فراخوانی شده‌اند.

پارامترها و آرگومان‌ها

مهم است که تفاوت بین پارامتر (Parameter) و آرگومان (Argument) را بدانیم. پارامترها متغیرهایی هستند که در تعریف متد لیست می‌شوند. آرگومان‌ها مقادیر واقعی هستند که هنگام فراخوانی متد به آن پاس داده می‌شوند. در مثال بالا، a و b پارامترهای متد Add هستند، در حالی که 5 و 3 آرگومان‌هایی هستند که به آن پاس داده شده‌اند.

پارامترهای اختیاری (Optional Parameters)

شما می‌توانید با اختصاص یک مقدار پیش‌فرض به یک پارامتر، آن را به یک پارامتر اختیاری تبدیل کنید. اگر فراخواننده‌ی متد برای آن پارامتر آرگومانی ارائه ندهد، از مقدار پیش‌فرض استفاده خواهد شد.

Copy Icon Program.cs
void Greet(string name, string prefix = "Mr.")
{
    Console.WriteLine($"Hello, {prefix} {name}");
}

// Calling with both arguments
Greet("Smith", "Dr."); // Output: Hello, Dr. Smith

// Calling without the optional argument, default value is used
Greet("Jones"); // Output: Hello, Mr. Jones

یک نکته‌ی مهم این است که تمام پارامترهای اختیاری باید بعد از پارامترهای اجباری در لیست پارامترهای متد قرار بگیرند.

آرگومان‌های نام‌گذاری شده (Named Arguments)

برای افزایش خوانایی، به خصوص در متدهایی با تعداد پارامترهای زیاد، می‌توانید هنگام فراخوانی متد، نام پارامتر را به همراه مقدار آن مشخص کنید. این کار به شما اجازه می‌دهد ترتیب آرگومان‌ها را نیز تغییر دهید.

Copy Icon Program.cs
void PrintUserDetails(string username, int age, bool isActive)
{
    // ... method body
    Console.WriteLine($"User: {username}, Age: {age}, Active: {isActive}");
}

// Calling using named arguments. The order does not matter.
PrintUserDetails(age: 30, isActive: true, username: "alice");

ارسال پارامتر با ارجاع (ref و out)

همانطور که در درس مربوط به انواع مقداری و ارجاعی به طور دقیق‌تر خواهیم دید، C# به صورت پیش‌فرض آرگومان‌ها را با مقدار (by value) به متدها ارسال می‌کند. این یعنی برای نوع‌های مقداری، یک کپی از مقدار و برای نوع‌های ارجاعی، یک کپی از ارجاع فرستاده می‌شود. اما گاهی نیاز داریم که خود متغیر اصلی را به متد بفرستیم تا متد بتواند آن را مستقیماً تغییر دهد. برای این کار از کلمات کلیدی ref و out استفاده می‌کنیم.

کلمه‌ی کلیدی ref

کلمه‌ی کلیدی ref به متد اجازه می‌دهد که به خود متغیر اصلی دسترسی داشته باشد و آن را تغییر دهد. متغیری که با ref ارسال می‌شود، باید قبل از فراخوانی متد، مقداردهی اولیه شده باشد.

Copy Icon Program.cs
void Triple(ref int x)
{
    x = x * 3;
}

int myNumber = 5;
Console.WriteLine($"Before: {myNumber}"); // Output: 5

// Pass the variable by reference
Triple(ref myNumber);

Console.WriteLine($"After: {myNumber}"); // Output: 15

همانطور که می‌بینید، متد Triple توانست مقدار متغیر اصلی myNumber را تغییر دهد، زیرا متغیر با ref ارسال شده بود.

کلمه‌ی کلیدی out

کلمه‌ی کلیدی out نیز شبیه به ref عمل می‌کند، با دو تفاوت کلیدی: 1. متغیری که با out ارسال می‌شود، نیازی به مقداردهی اولیه ندارد. 2. متد موظف است قبل از پایان، حتماً یک مقدار به پارامتر out اختصاص دهد. این کلمه‌ی کلیدی معمولاً زمانی استفاده می‌شود که یک متد بخواهد بیش از یک مقدار را برگرداند.

Copy Icon Program.cs
bool TryDivide(double numerator, double denominator, out double result)
{
    if (denominator == 0)
    {
        result = 0; // Must assign a value before returning
        return false;
    }
    
    result = numerator / denominator;
    return true;
}

double divisionResult; // No need to initialize
if (TryDivide(10, 2, out divisionResult))
{
    Console.WriteLine($"Result: {divisionResult}"); // Output: 5
}

متد TryDivide وضعیت موفقیت عملیات را به صورت bool برمی‌گرداند و نتیجه‌ی تقسیم را از طریق پارامتر out به بیرون منتقل می‌کند. این الگو در بسیاری از متدهای خود فریم‌ورک .NET (مانند int.TryParse) استفاده می‌شود. البته امروزه با وجود تاپل‌ها، استفاده از out برای بازگرداندن چند مقدار کمتر شده است.

سربارگذاری متدها (Method Overloading)

سربارگذاری به شما این امکان را می‌دهد که چندین متد با نام یکسان اما با لیست پارامترهای متفاوت در یک نوع (کلاس یا ساختار) تعریف کنید. تفاوت در لیست پارامترها می‌تواند در تعداد یا نوع پارامترها باشد. کامپایلر C# به صورت هوشمند، بر اساس آرگومان‌هایی که شما هنگام فراخوانی متد ارسال می‌کنید، نسخه‌ی صحیح متد را انتخاب می‌کند.

Copy Icon Program.cs
// Overloaded methods
int Add(int a, int b)
{
    return a + b;
}

double Add(double a, double b)
{
    return a + b;
}

int Add(int a, int b, int c)
{
    return a + b + c;
}

// Compiler chooses the correct overload based on arguments
Console.WriteLine(Add(2, 3)); // Calls the first overload
Console.WriteLine(Add(2.5, 3.7)); // Calls the second overload
Console.WriteLine(Add(2, 3, 5)); // Calls the third overload

سربارگذاری یک ابزار قدرتمند برای ایجاد API های انعطاف‌پذیر و خوانا است، زیرا به کاربران اجازه می‌دهد یک عملیات منطقی واحد (مانند "جمع کردن") را با انواع داده‌های مختلف انجام دهند بدون اینکه نیاز به به خاطر سپردن نام‌های متفاوت برای هر حالت داشته باشند. توجه داشته باشید که نوع بازگشتی متد در سربارگذاری نقشی ندارد.