الدوال في C#: Methods والمعاملات المسماة
الدوال تحوّل البرنامج الطويل إلى قطع صغيرة واضحة، كل قطعة لها اسم ووظيفة واحدة. في C# تسمى الدوال Methods، وفيها ميزات مريحة جداً: صيغة مختصرة في سطر واحد، وقيم افتراضية، ومعاملات تُكتب بأسمائها. في هذا الدرس ستكتب دوالك الخاصة وتستخدم كل هذه الميزات.
تعريف دالة
Section titled “تعريف دالة”Greet();Console.WriteLine(Add(3, 4));
static void Greet(){ Console.WriteLine("أهلاً بك في C#!");}
static int Add(int a, int b){ return a + b;}أهلاً بك في C#!7static int Add(int a, int b): نوع القيمة المرجعةint، ثم الاسم، ثم المعاملات بأنواعها.void: الدالة لا تُرجع شيئاً.return: تُرجع القيمة وتُنهي الدالة.- العُرف في C#: أسماء الدوال بصيغة PascalCase (كل كلمة تبدأ بحرف كبير) مثل
AddوPriceAfterDiscount.
في البرامج ذات «الجمل العلوية» (Top-level Statements) مثل هذا، تكتب الأوامر في أعلى الملف، والدوال في أسفله. وكلمة static تجعل الدالة لا تعتمد على كائن، وستفهمها أكثر في درس الكلاسات.
الدوال المختصرة بـ =>
Section titled “الدوال المختصرة بـ =>”إذا كانت الدالة تُرجع تعبيراً واحداً:
static int Square(int x) => x * x;
static string MakeTea(int sugar = 2) => $"شاي بـ {sugar} ملاعق سكر";Square(5) تُرجع 25. والسهم => يساوي { return ...; }. هذه الصيغة تسمى Expression-bodied Members.
القيم الافتراضية والمعاملات المسماة
Section titled “القيم الافتراضية والمعاملات المسماة”Console.WriteLine(MakeTea());Console.WriteLine(MakeTea(0));شاي بـ 2 ملاعق سكرشاي بـ 0 ملاعق سكرsugar = 2 قيمة افتراضية تُستخدم إذا لم ترسل قيمة. والمعاملات ذات القيم الافتراضية تأتي في آخر القائمة.
وتستطيع عند الاستدعاء كتابة اسم كل معامل، فلا يهم الترتيب:
static string CreateUser(string name, int age, string city = "القاهرة"){ return $"{name} ({age} سنة) من {city}";}Console.WriteLine(CreateUser("عمر", 15));Console.WriteLine(CreateUser(age: 20, name: "منى", city: "جدة"));عمر (15 سنة) من القاهرةمنى (20 سنة) من جدةالمعاملات المسماة تجعل الاستدعاء مقروءاً مثل الجملة، خاصة عندما تكثر المعاملات أو تتشابه أنواعها، مثل SendEmail(to: ..., subject: ..., body: ...).
التمرير بالقيمة و ref
Section titled “التمرير بالقيمة و ref”static void TryToChange(int x){ x = 100;}
static void AddPoints(ref int score, int bonus){ score += bonus;}int value = 5;TryToChange(value);Console.WriteLine(value);
int score = 10;AddPoints(ref score, 5);Console.WriteLine(score);515- افتراضياً، C# ترسل نسخة من القيمة، فلم تتغير
value. - مع
ref، ترسل المتغير الأصلي نفسه، فتغيرتscore. ولاحظ أنrefتُكتب في التعريف وفي الاستدعاء معاً، لتكون واضحة لكل من يقرأ الكود.
تخيّل الفرق: بدون ref تعطي صديقك صورة من ورقتك، ومع ref تعطيه الورقة نفسها.
لكن الأسلوب المفضل غالباً هو أن تُرجع الدالة القيمة الجديدة: score = AddBonus(score, 5);، فهو أوضح، ونستخدم ref فقط عند الحاجة الحقيقية.
Lambda و Func
Section titled “Lambda و Func”الدالة في C# يمكن أن تكون قيمة تخزنها في متغير:
Func<int, int> twice = x => x * 2;Console.WriteLine(twice(21));42x => x * 2: دالة مجهولة (Lambda): المعامل قبل السهم، والنتيجة بعده.Func<int, int>: نوع الدالة: تأخذintوتُرجعint. (آخر نوع بين< >هو نوع القيمة المرجعة دائماً.)
ستستخدم الـ Lambda كثيراً مع القوائم في الدرس القادم، مثل: grades.Where(g => g >= 75).
دوال Math الجاهزة
Section titled “دوال Math الجاهزة”Console.WriteLine(Math.Max(4, 9));Console.WriteLine(Math.Sqrt(16));Console.WriteLine(Math.Pow(2, 10));Console.WriteLine(Math.Round(3.6));9410244لاحظ أن Math.Sqrt(16) نوعها double، لكنها تُطبع 4 لأن C# لا تطبع الأصفار غير الضرورية.
جرّب بنفسك
Section titled “جرّب بنفسك”Console.WriteLine(PriceAfterDiscount(200));Console.WriteLine(PriceAfterDiscount(200, percent: 25));
static double PriceAfterDiscount(double price, double percent = 10) => price - price * percent / 100;180150تحدٍّ: اكتب دالة Grade(int score) بتعبير switch تُرجع «ممتاز» أو «ناجح» أو «راسب»، ثم خزّنها في Func<int, string> واستدعها من المتغير.
أخطاء شائعة
Section titled “أخطاء شائعة”- نسيان return: خطأ
not all code paths return a valueعندما يوجد طريق في الدالة لا يُرجع قيمة. - نسيان ref في الاستدعاء: إذا كان المعامل
ref، يجب كتابةrefعند الاستدعاء أيضاً. - قيمة افتراضية قبل معامل إجباري:
void F(int a = 1, int b)خطأ ترجمة.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
أي استدعاء صحيح للدالة static void Order(string item, int qty = 1)؟
مع المعاملات المسماة لا يهم الترتيب، لكن item ليس له قيمة افتراضية فلا يمكن حذفه.
سؤال
ماذا يعني النوع Func<string, int>؟
في Func آخر نوع هو القيمة المرجعة، وما قبله أنواع المعاملات.
الخلاصة
Section titled “الخلاصة”- الدالة: نوع مرجع واسم بصيغة PascalCase ومعاملات، و
voidلا تُرجع شيئاً. =>تختصر الدالة ذات التعبير الواحد.- القيم الافتراضية في آخر المعاملات، والمعاملات المسماة تجعل الاستدعاء واضحاً.
- C# ترسل نسخة افتراضياً، و
refفي التعريف والاستدعاء لتعديل الأصل. - Lambda مثل
x => x * 2، ونوعهاFunc<المدخل, المخرج>.