التعامل مع Methods في C#
في التعامل مع الدوال( Methods) في سي شارب...!! ماذا نعني بنطاق الداله بالـ Method Scope ..؟!!! وكيف نجعل الدالة تؤثر على قيم خارجها عند تمرير القيم لها..؟! ماذا يعني الـ Overload وكيف يكون مع الدوال في سي شارب..؟؟!! وكيف يمكن للدالة تقوم باستدعاء نفسها.. ماذا يعني الـ Recursion !!
تكلمنا في مقال الدوال Methods في سي شارب عرفنا الدوال وطريقة انشائها.واستكمالاً للحديث عن الدوال Methods نشرح في هذا المقال التعامل مع الدوالMethods في البرمجة عموماً و سنستخدم أمثلة من C# عليها يشرح المقال Method Scope و المفاهيم Pass by Value or by Reference وأيضاً Overload و Recursion . لنبدأ..
في هذا المقال نتعرف على :
- نطاق الدالة Method Scope في C# .
- تمرير البيانات للدوال Methods في C# .
- مفهوم Methods Overload في C# .
- مفهوم Recursion Methods في C# .
نطاق الدالة Method Scope في C#
احد أهم مصطلحات البرمجة النطاق Scope وفي الدوال يعتبر فهم النطاق Scope الخاص بالـ Methods مهم جداً في التعامل مع الدوال في سي شارب. ونطاق الدالة Method scope هو المساحة من البرنامج التي يمكن فيها استدعاء الدالة Method. في سي شارب كل دالة لابد ان تكون داخل Class حتى الدالة Main الدالة المشغلة للتطبيق لابد ان تكون داخل Class . وتلقائياً تكون حدود النطاق للدالة الـ Class المعرفة به فقط . و يمكن التحكم بحدود مساحة النطاق للدالة بواسطة كلمات معينة تستخدم في بيان الإعلان عن الدالة.
إن نطاق الدالة Method Scope هو تحديد لمساحة إمكانية الوصول إلى الدالة واستخدامها، فإذا أردنا أن تكون الدالة معرفة خارج الـ Class الخاص بها فنستخدم الكلمة المحجوزة public في بيان الإعلان عن الدالة وان اردنا ان تكون الدالة خاصة بهذا الـ Class سوف نستخدم الكلمة المجوزة private في هذه الحالة ستكون الدالة معرفة فقد داخل الـ Class الخاص بها.
يشرح الشكل التالي مفهوم نطاق الدالة Method Scope في لغة سي شارب :
كما يمكن تحديد نطاق الدالة بـ Class الخاص بها والـ Classes الوارثة منه فقط بواسطة الكلمة المحجوزة protected ستتضح معنا أكثر عندما نتكلم عن مفهوم الوارثة الـ Inheritance بين الـ Classes.
هنا مثال على استخدام كلمة public التي تسمح باستدعاء الدالة خارج نطاقها:
class Program
{
public static void Main(string[] args)
{
int a = 0;
Console.WriteLine(a);
//Calling increment method from incremented class
incremented.increment( a);
Console.WriteLine(a);
}
}
//Declaring incremented class
class incremented{
public static void increment ( int x )
{
x =+1;
Console.WriteLine(x);
}
}
وفي حال كانت الدالة increment هنا private أي خاصة ضمن نطاق incremented Class واردنا استدعاؤها خارج هذا الـ Class سيعطي الـ Compiler خطأ ولن نستطيع الوصول للدالة.
نلاحظ ايضاً أنه عند الاستدعاء تم كتابة اسم الـ Class قبل اسم الدالة هذا لأن الدالة static وهي الطريقة المستخدمة للتعامل مع هذا النوع من الدوال وإلا لابد من إنشاء Object لـلـ Class الموجودة فيه الدالة المراد استدعائها بعض الـ Classes الموجودة في بـ .NET Framework Class Library leg مثل Math class تحتوى على دول من نوع static لنرى مثال :
class Program
{
public static void Main(string[] args)
{
Console.WriteLine(Math.Abs(-1));
}
}
تمرير البيانات للدوال Methods في C#
من المهم في التعامل مع الدوال Methods في لغة سي شارب فهم الطريقة التي يتم بها تمرير البيانات المراد معالجتها للدالة. نعني بطُرق تمرير الـ Parameters والـ Arguments .
حيث أن الـ Arguments هي القيم أو المتغيرات التي تستخدم في بيان الاستدعاء اي التي ترسل الى الـ Method . أما الـ Parameters فهي المتغيرات الموجودة في بيان الإعلان عن الـ Method والتي تستخدم داخل الدالة (أي القيم التي تستقبلها الدالة و تسندها إلى متغيراتها).
وعند الاستدعاء يجب ان تتطابق انواع الـ Arguments وترتيبها مع الـ Parameters ففي حال عدم التطابق سيحدث الـ Compiler خطأ.
في C# يمكن اضافة قيم افتراضية في حال الإستدعاء دون إعطاء Arguments في هذه الحال ستستخدم القيم الافتراضية وهنا مثال على طريقة استخدام القيم الإفتراضية في التعامل مع الدوال في سي شارب:
class Program
{
public static void Main(string[] args)
{
PrintName("Sara");
PrintName("Nora");
PrintName();
}
static void PrintName (string Name = "Unknown name")
{
Console.WriteLine(Name);
}
}
لتكـن النتيـجـة
Sara Nora Unknown name
وعند عدم وجود قيم افتراضية لابد من ارسال الـ Arguments وفي حال لم يتم الارسال سيعطي الـ Compiler خطأ.
و في التعامل مع Methods في C# هنالك طريقتان لإرسال Arguments الى الـ Method وهي:
- تمرير نسخة القيم وتسمى هذه الطريقة "تمرير القيمة Pass by Value ".
- تمرير قيمة المتغير الاصلية وتسمى هذه الطريقة "تمرير المتغير Pass by Reference ".
تمرير القيمة Pass by Value
وهذه الحالة هي الحالة الافتراضية في ارسال قيم المتغيرات Arguments هنا تأخذ الدالة نسخة من قيمة المتغيرات المرسلة وسوف تستخدمها في نطاق الدالة دون أن تتأثر قيمة المتغير الأصلي الموجود خارج الدالة.
لنرى في هذا المثال سنقوم بطباعة قيم المتغير الموجود في Main قبل وبعد استدعاء الدالة ولاحظ / ي النتائج :
class Program
{
public static void Main(string[] args)
{
int a = 0;
Console.WriteLine(a);
increment(a);
Console.WriteLine(a);
}
static void increment (int x )
{
++x;
Console.WriteLine(x);
}
}
لتكـن النتيـجـة
0 1 0
في المثال نلاحظ ان قيمة المتغير في الدالة Main لم تتأثر بعد الاستدعاء هذا لأن الدالة وقت الاستدعاء اخذت نسختها الخاصة من قيمة المتغير دون أن يؤثر هذا على قيمة المتغير خارجها.
تمرير المتغير Pass by Reference
في التعامل مع الدوال في C# يعني مفهوم تمير المتغير Pass by Reference أن الدالة تقوم بالتأثير على قيمة المتغير خارجها وفي هذه الحالة سنستخدم الكلمة المحجوزة ref وبهذا سوف تصل الدالة الى عنوان المتغير في الذاكرة (Reference) وتقوم بإستخدام القيمة الموجودة في هذا العنوان.
لنرى مثال على طريقة تمرير المتغيرPass by Reference في لغة C# :
class Program
{
public static void Main(string[] args)
{
int a = 0;
Console.WriteLine(a);
increment(ref a);
Console.WriteLine(a);
}
static void increment ( ref int x )
{
++x;
Console.WriteLine(x);
}
}
لتكـن النتيـجـة
0 1 1
هنالك طريقة اخرى ايضاً ستجعل الدالة تؤثر على قيمة المتغير خارجها وهي استخدام الكلمة المحجوزة out في بيان الإعلان عن الدالة والتي تقوم بإنشاء Output parameter فعند استخدام هذه الكلمة سقوم الـ Compiler بالتعامل مع القيم الممرة بطريقة Pass by Reference.
class Program
{
public static void Main(string[] args)
{
int a = 0;
Console.WriteLine(a);
increment(out a);
Console.WriteLine(a);
}
static void increment (out int x )
{
x =+1;
Console.WriteLine(x);
}
}
لتكـن النتيـجـة
0 1 1
لاحظ تطابق النتائج في المثالين السابقين.
مفهوم Methods Overload في C#
من المفاهيم الأساسية التي يجب معرفتها عند التعامل مع الدوال Methods في C# هو مفهوم الـ Overload. فعند الإعلان عن الـ Method لابد ان يكون للدالة اسم فريد لا يتطابق مع دالة أخرى في نفس النطاق المعرفة فيه وإلا سيعطي الـ Compiler خطأ.
في الحديث عن تمرير البيانات للدالة ذكرنا انه يجب ان تتطابق انواع الـ Arguments وترتيبها مع الـ Parameters عند الاستدعاء. ولكن ماذا اذا كان لدينا أكثر من دالة معرفة في نفس النطاق وتحمل نفس الاسم ولكن أنواع وترتيب الـ Parameters مختلف في كل داله عن الاخرى هذا هو باختصار "مفهوم الـ Overload" ويوضح المثال التالي طريقة عمل الـ Overload :
class Program
{
public static void Main(string[] args)
{
int a = 1, b = 2;
double c = 2.5, d = 3;
Add(a,b);
Add(c,d );
}
public static void Add(int x, int y){
Console.WriteLine("The result for addition two integer numbers is {0}", x + y );
}
public static void Add(double x, double y){
Console.WriteLine("The result for addition two float numbers is {0}", x + y );
}
}
لتكـن النتيـجـة
The result for addition two integer numbers is 3 The result for addition two float numbers is 5.5
كما هو موضح في المثال قمنا بتعريف دالتين بإسم Add وكلاهما تقوم بجمع القيم المرسلة لها ولكن كل واحدة منها تستقبل نوع بيانات مختلف هنا قام الـ Compiler باستدعاء الدالة المناسبة حسب نوع البيانات للـ Arguments .هذا هو باختصار مفهوم Overload Methods وتدعم كثير من لغات البرمجة الـ Overload.
مفهوم Recursion Methods في C#
طريقة العودية أو ما يسمى Recursion تعتبر من الأساسيات في التعامل مع الدوال Methods . و Recursion هو طريقة تجعل الدالة تستدعي نفسها.
عرفنا كيف تقوم جُمل التكرار بتكرار التعليمات البرمجية وتقوم طريقة الـ Recursion كذلك بتكرار بيان تعليمات الدالة عن طريق تكرار استدعاء الدالة لنفسها حيث يتم تقسيم تعليمات الدالة الى قسمين إما أن يعاود الاستدعاء للدالة او ينهي تنفيذها وهذا بعد اختبار قيمة لمتغير معين في الدالة في كل مرة يتم فيها الاستدعاء وعند وصول المتغير الى قيمة معينة سيوقف عملية الاستدعاء المتكرر وينهي التنفيذ.
ويسمى وصول المتغير للقيمة التي تنهي بها عملية الاستدعاء base case وعدم ضبط التعليمات للوصول الى هذه القيمة يعد خطأ وقد يؤدي الى استدعاء لانهائي.
لنرى مثال يوضح مفهوم الـ Recursion بواسطة تعليمات لغة سي شارب ، في المثال سنقوم بإنشاء دالة تحسب حاصل ضرب القيم المرسلة لها:
class Program
{
public static void Main(string[] args)
{
Console.WriteLine(Multiplication(5, 2)) ;
Console.WriteLine(Multiplication(3, 2)) ;
Console.WriteLine(Multiplication(5, 3)) ;
Console.WriteLine(Multiplication(5, 0)) ;
Console.WriteLine(Multiplication(0, 3)) ;
}
public static int Multiplication (int x, int y){
if ( y == 0) //base case
return 0;
//recursion step
else return (x + Multiplication(x ,y-1));
}
}
لتكـن النتيـجـة
10 6 15 0 0
الأمثلة لهذا المقال متوفرة هنا.
إلى هنا ينتهي هذا المقال الذي تكلم عن بعض الأساسيات التي يجب معرفتها عند التعامل مع الدوال Methods في لغة C# . شرح المقال مفاهيم مهمة في البرمجة مثل Scope و Pass by value or reference بالإضافة الى مفهومي Overload و Recursion .