مقدمه
متدها (Methods) یکی از اساسیترین واحدهای سازنده در هر برنامه C# هستند. یک متد، بلوکی
از کد است که یک وظیفهی مشخص را انجام میدهد و میتوان آن را بارها و بارها از نقاط مختلف برنامه
فراخوانی کرد. استفاده از متدها به ما کمک میکند تا کدهای خود را سازماندهی کنیم، از تکرار کد (بر
اساس اصل DRY - Don't Repeat Yourself) جلوگیری کرده و برنامههایی خواناتر و با قابلیت نگهداری
بالاتر بنویسیم. در درسهای گذشته ما به طور مداوم از متدها استفاده کردهایم، مانند متد Console.WriteLine(). در این درس، به طور کامل با نحوهی تعریف،
فراخوانی و ویژگیهای پیشرفتهتر متدها در C# آشنا خواهیم شد.
تعریف و فراخوانی یک متد
یک متد از دو بخش اصلی تشکیل شده است: امضای متد (Method Signature) و
بدنهی متد (Method Body). امضای متد، اطلاعات کلی متد را مشخص میکند و بدنهی
آن، شامل دستوراتی است که باید اجرا شوند.
اجزای یک متد
امضای یک متد شامل موارد زیر است:
- سطح دسترسی (Access Modifier): مشخص میکند که متد از کجا قابل دسترسی است
(مثلاً public یا private). این
موضوع در فصلهای آینده به تفصیل بررسی میشود.
- مقدار بازگشتی (Return Type): نوع دادهای که متد پس از اتمام کار خود
برمیگرداند. اگر متد مقداری را برنگرداند، از کلمهی کلیدی void
استفاده میشود.
- نام متد (Method Name): یک نام توصیفی برای متد.
- پارامترها (Parameters): لیستی از متغیرها که به عنوان ورودی به متد داده
میشوند. این بخش اختیاری است.
Program.cs
void SayHello()
{
Console.WriteLine("Hello, World!");
}
int Add(int a, int b)
{
int sum = a + b;
return sum;
}
SayHello();
int result = Add(5, 3);
Console.WriteLine(result);
در کد بالا، ابتدا دو متد SayHello و Add تعریف شدهاند. متد SayHello هیچ ورودی (پارامتر)
ندارد و هیچ خروجی هم برنمیگرداند (مقدار بازگشتی آن void است). متد
Add دو پارامتر از نوع int دریافت کرده و حاصل جمع آنها را که یک
int است، با استفاده از کلمهی کلیدی return برمیگرداند. سپس در ادامه، این دو متد فراخوانی شدهاند.
پارامترها و آرگومانها
مهم است که تفاوت بین پارامتر (Parameter) و آرگومان (Argument)
را بدانیم. پارامترها متغیرهایی هستند که در تعریف متد لیست میشوند. آرگومانها مقادیر واقعی هستند
که هنگام فراخوانی متد به آن پاس داده میشوند. در مثال بالا، a و b پارامترهای متد Add
هستند، در حالی که 5 و 3 آرگومانهایی هستند که به آن پاس داده شدهاند.
پارامترهای اختیاری (Optional Parameters)
شما میتوانید با اختصاص یک مقدار پیشفرض به یک پارامتر، آن را به یک پارامتر اختیاری تبدیل کنید.
اگر فراخوانندهی متد برای آن پارامتر آرگومانی ارائه ندهد، از مقدار پیشفرض استفاده خواهد شد.
Program.cs
void Greet(string name, string prefix = "Mr.")
{
Console.WriteLine($"Hello, {prefix} {name}");
}
Greet("Smith", "Dr.");
Greet("Jones");
یک نکتهی مهم این است که تمام پارامترهای اختیاری باید بعد از پارامترهای اجباری در لیست
پارامترهای متد قرار بگیرند.
آرگومانهای نامگذاری شده (Named Arguments)
برای افزایش خوانایی، به خصوص در متدهایی با تعداد پارامترهای زیاد، میتوانید هنگام فراخوانی متد،
نام پارامتر را به همراه مقدار آن مشخص کنید. این کار به شما اجازه میدهد ترتیب آرگومانها را نیز
تغییر دهید.
Program.cs
void PrintUserDetails(string username, int age, bool isActive)
{
Console.WriteLine($"User: {username}, Age: {age}, Active: {isActive}");
}
PrintUserDetails(age: 30, isActive: true, username: "alice");
ارسال پارامتر با ارجاع (ref و out)
همانطور که در درس مربوط به انواع مقداری و ارجاعی به طور دقیقتر خواهیم دید، C# به صورت پیشفرض آرگومانها
را با مقدار (by value) به متدها ارسال میکند. این یعنی برای نوعهای مقداری، یک
کپی از مقدار و برای نوعهای ارجاعی، یک کپی از ارجاع فرستاده میشود. اما گاهی نیاز داریم که خود
متغیر اصلی را به متد بفرستیم تا متد بتواند آن را مستقیماً تغییر دهد. برای این کار از کلمات کلیدی
ref و out استفاده میکنیم.
کلمهی کلیدی ref
کلمهی کلیدی ref به متد اجازه میدهد که به خود متغیر اصلی دسترسی
داشته باشد و آن را تغییر دهد. متغیری که با ref ارسال میشود،
باید قبل از فراخوانی متد، مقداردهی اولیه شده باشد.
Program.cs
void Triple(ref int x)
{
x = x * 3;
}
int myNumber = 5;
Console.WriteLine($"Before: {myNumber}");
Triple(ref myNumber);
Console.WriteLine($"After: {myNumber}");
همانطور که میبینید، متد Triple توانست مقدار متغیر اصلی myNumber را تغییر دهد، زیرا متغیر با
ref ارسال شده بود.
کلمهی کلیدی out
کلمهی کلیدی out نیز شبیه به ref عمل
میکند، با دو تفاوت کلیدی:
1. متغیری که با out ارسال میشود، نیازی به مقداردهی اولیه ندارد.
2. متد موظف است قبل از پایان، حتماً یک مقدار به پارامتر out اختصاص دهد.
این کلمهی کلیدی معمولاً زمانی استفاده میشود که یک متد بخواهد بیش از یک مقدار را برگرداند.
Program.cs
bool TryDivide(double numerator, double denominator, out double result)
{
if (denominator == 0)
{
result = 0;
return false;
}
result = numerator / denominator;
return true;
}
double divisionResult;
if (TryDivide(10, 2, out divisionResult))
{
Console.WriteLine($"Result: {divisionResult}");
}
متد TryDivide وضعیت موفقیت عملیات را به صورت bool برمیگرداند و
نتیجهی تقسیم را از طریق پارامتر out به بیرون منتقل میکند. این
الگو در بسیاری از متدهای خود فریمورک .NET (مانند int.TryParse) استفاده میشود. البته امروزه با وجود تاپلها، استفاده
از out برای بازگرداندن چند مقدار کمتر شده است.
سربارگذاری متدها (Method Overloading)
سربارگذاری به شما این امکان را میدهد که چندین متد با نام یکسان اما با
لیست پارامترهای متفاوت در یک نوع (کلاس یا ساختار) تعریف کنید. تفاوت در لیست
پارامترها میتواند در تعداد یا نوع پارامترها باشد. کامپایلر C# به صورت هوشمند، بر
اساس آرگومانهایی که شما هنگام فراخوانی متد ارسال میکنید، نسخهی صحیح متد را انتخاب میکند.
Program.cs
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;
}
Console.WriteLine(Add(2, 3));
Console.WriteLine(Add(2.5, 3.7));
Console.WriteLine(Add(2, 3, 5));
سربارگذاری یک ابزار قدرتمند برای ایجاد API های انعطافپذیر و خوانا است، زیرا به کاربران اجازه
میدهد یک عملیات منطقی واحد (مانند "جمع کردن") را با انواع دادههای مختلف انجام دهند بدون اینکه
نیاز به به خاطر سپردن نامهای متفاوت برای هر حالت داشته باشند. توجه داشته باشید که نوع بازگشتی
متد در سربارگذاری نقشی ندارد.