المحتوى عن 'dot.net'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • الإدارة والقيادة
  • مقالات ريادة أعمال عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML
    • HTML5
  • CSS
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • التسويق بالرسائل النصية القصيرة
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 3 نتائج

  1. المتغيرات Variables سبق وأن ذكرنا في الدرس الأوّل أنّه يوجد نمطان أساسيّان لأنواع المتغيّرات في سي شارب، وهما: أنواع قيمة value types وأنواع مرجعيّة reference types. تشتمل أنواع القيمة على الأنواع المُدمجة built-in في اللغة مثل int و float و decimal و double و bool وجميع الأنواع المُعرّفة كبنية struct. سنتحدّث عن البنى في درس لاحق. في حين تشتمل الأنواع المرجعيّة على أيّ نوع آخر وهذا يشتمل على عدد لا يحصى من الأنواع، فيكفيك أن تعرف مثلًا أنّ جميع الأنواع الموجودة في مكتبة FCL هي أنواع مرجعيّة، بالإضافة إلى أنّ أي نوع جديد (على شكل صنف class) ينشئه المستخدم يُعتبر نوعًا مرجعيًّا. ومن المفيد أن تعلم أنّ النوع المُضمّن string هو نوع مرجعيّ أيضًا. يكمن الفرق الأساسي بين أنواع القيمة والأنواع المرجعيّة في مكان وطريقة تخزين قيم المتغيّرات المصرّح عنها بواسطتها. فعند التصريح عن متغيّر من نوع قيمة، تُخزّن أي قيمة يتمّ إسنادها إليه ضمن المتغيّر نفسه أو بمعنى أدق تُخزّن في ذاكرة المُكدّس Stack Memory، أمّا المتغيّر المصرّح عنه على أنّه نوع مرجعيّ فالّذي يُخزّن ضمنه هو العنوان إلى موقع في الذاكرة. هذا الموقع موجود ضمن ما يُسمّى بذاكرة الكَوْمَة Heap Memory. انظر إلى الشكل التوضيحي التالي. حيث صرّحنا عن المتغيّر x من النوع int وخزّنّا القيمة 5 ضمنه. وبما أنّ int هو نوع قيمة، لذلك سيكون المتغيّر مع القيمة المخزّنة فيه ضمن المكدّس Stack. أمّا بالنسبة للمتغيّر s فهو من النوع string وقد أسندنا إليه النص "!Hello" وبما أنّ النوع string هو نوع مرجعيّ كما أسلفنا لذلك فالقيمة التي ستكون مخزّنة ضمن المتغيّر s في الحقيقة ليست النص "!Hello" إنّما العنوان address الذي يُشير إلى موقع ضمن الكومة Heap موجود ضمنه النص "!Hello"، وهذا بالمناسبة ليس سلوكًا تنفرد به سي شارب، بل هو موجود في لغات أخرى مثل ++C و C. سنتوسّع في هذا الموضوع قليلًا عندما نتحدّث عن الأصناف والكائنات لاحقًا في هذه السلسلة. يمكن استخدام أيّ مزيج من الحروف والأرقام عند تسمية المتغيّرات، بشرط أن يكون أوّل محرف في اسم المتغيّر حرفًا وليس رقمًا. كما لا يجوز أن يحتوي اسم المتغيّر على فراغات ولا يجوز أيضًا أن يكون مماثلًا لكلمة محجوزة في سي شارب مثل new أو class أو غيرها، ولا يجوز أن يحتوي على رموزًا خاصّة مثل & و$ و#، ولكن يُعتبر الرمز (_) underscore حرفًا ويجوز الابتداء به. الأنواع المضمنة ومجالاتها الأنواع المُضمّنة هي الأنواع الموجودة ضمنًا في لغة سي شارب وفي إطار عمل دوت نت عمومًا. سنستعرض في الجدول التالي هذه الأنواع. لاحظ أنّ عمود "الاسم" يحتوي على أسماء الأنواع المستخدمة في سي شارب، في حين يحتوي العمود الذي يليه مباشرةً على اسم نفس النوع ولكن ضمن منصّة دوت نت. في الحقيقة يمكننا استخدام أي تسمية نرغبها ولكنّ الأسهل والأفضل هي في استخدام أسماء الأنواع في سي شارب. يعود سبب وجود أسماء أنواع مختلفة في إطار عمل دوت نت هو أنّه بإمكان أي لغة برمجة ضمن منصة دوت نت استخدام نفس هذه الأنواع ضمنها. الاسم النوع الموافق في منصّة دوت نت القيم التي يقبلها الحجم في الذاكرة 1 bool System.Boolean true أو false 2 sbyte System.SByte من128- حتى 127 8 bits 3 byte System.Byte من 0 حتى 255 8 bits 4 short System.Int16 من 32,768- حتى 32,767 16 bits 5 ushort System.UInt16 من 0 حتى 65,535 16 bits 6 int System.Int32 من 2,147,483,648- حتى 2,147,483,647 32 bits 7 uint System.UInt32 من 0 حتى 4,294,967,295 32 bits 8 long System.Int64 من 9,223,372,036,854,775,808- حتى 9,223,372,036,854,775,807 64 bits 9 ulong System.UInt64 من 0 حتى 18,446,744,073,709,551,615 64 bits 10 char System.Char من U+0000 حتى U+ffff 16 bits 11 float System.Single من 3.4*1038- حتى +3.4*1038 32 bits 12 double System.Double من ±5.0*10-324 حتى ±1.7*10308 64 bits 13 decimal System.Decimal (-7.9*1028 to 7.9*1028)/(100 to 28) 128 bits 14 string System.String حسب حدود الذاكرة 15 object System.Object يمكن تخزين بيانات من أيّ نوع ضمن المتغيّرات من النوع object الأنواع من 2 حتى 9 هي أنواع صحيحة لا تقبل أعدادًا ذات فاصلة عشريّة. أما الأنواع من 11 حتى 13 فهي أنواع تقبل أعداد ذات فاصلة عشريّة وتختلف فيما بينها في مجالات الأعداد التي تقبلها ودقّة تلك الأعداد بالنسبة لعدد الخانات على يمين الفاصلة العشريّة. النوع char مخصّص للمتغيّرات التي تسمح بتخزين محرف character واحد فقط، وهو نوع يدعم ترميز Unicode، يُعتبر أي محرف موضوع ضمن علامتي اقتباس مفردتين مثل 'a' من نوع char. في الحقيقة أنّ النوع string يُعبّر عن سلسلة من المحارف من نوع char. النوع object هو الأب العام لجميع الأنواع في إطار العمل دوت نت ومنه تنحدر جميع الأنواع الأخرى مهما كانت، سنصادفه في هذه السلسلة مرّةً أخرى. العوامل Operators تدعم سي شارب نوعين من العوامل بشكل أساسيّ: عوامل أحاديّة unary operators وعوامل ثنائيّة binary operators. سنتحدّث في هذا الدرس عن أكثر العوامل استخدامًا في سي شارب. العوامل الأحادية لهذه العوامل أسبقيّة أعلى في الحساب من العوامل الثنائيّة، وهي تشمل العديد من العوامل يلخّص الجدول التالي أهمّها، انظر إلى الأمثلة العمليّة التي ستأتي بعد الجدول لمعرفة كيفيّة استخدامها: العامل الوصف الاستخدام ! عامل النفي المنطقي وهو عامل يُطبّق على القيم المنطقيّة من النوع bool. x! ~ عامل المتمّم الثنائي bitwise complement وهو عبارة عن عامل نفي ولكن على مستوى البتّات bits. x~ ++ لهذا العامل شكلان يعمل كلّ منها على زيادة قيمة متغيّر عددي بمقدار 1، ويختلفان فقط في توقيت هذه الزيادة. x++ عامل زيادة بادئ. ++x عامل زيادة لاحق. -- لهذا العامل شكلان أيضًا، يعمل كلّ منها على إنقاص قيمة متغيّر عددي بمقدار 1، ويختلفان فقط في توقيت هذا الإنقاص. x-- عامل إنقاص بادئ. --x عامل إنقاص لاحق. (T) وهو عامل التحويل بين الأنواع casting. وهو عامل مهم جدًّا سنصادفه مرارًا في هذه السلسلة. يمكن استبدال الحرف T باسم أيّ نوع يخطر على بالك مثل int وdouble وstring وغيرها. طريقة استخدامه هو في وضع النوع المراد التحويل إليه بين قوسين ونضعها جميعًا قبل القيمة التي نريد تحويلها مثل (int(x لتحويل قيمة x إلى قيمة من النوع int. فهم عاملي الزيادة والإنقاص شغّل برنامج Visual Studio 2015 Community وأنشئ مشروعًا جديدًا من النوع Console Application سمّه UnaryOperatorsTest1 ثم استبدل محتويات الملف Program.cs بالشيفرة التالية: 1 using System; 2 3 4 namespace UnaryOperatorsTest 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 int i = 1; 11 12 Console.WriteLine("Using of pre-increment operator (++i):"); 13 Console.WriteLine("Current value of i is {0}, and after applying ++i, the value of i becomes {1}", i, ++i); 14 Console.WriteLine(new string('-', 40)); 15 16 Console.WriteLine(); 17 i = 1; 18 19 Console.WriteLine("Using of post-increment operator (i++):"); 20 Console.WriteLine("Current value of i is {0}, and after applying i++, the value of i becomes {1}", i, i++); 21 Console.WriteLine(new string('-', 40)); 22 } 23 } 24 } نفّذ البرنامج باستخدام Ctrl+F5 (أو من القائمة Debug > Start Without Debugging) ستحصل على الخرج التالي: sing of pre-increment operator (++i): Current value of i is 1, and after applying ++i, the value of i becomes 2 ---------------------------------------- Using of post-increment operator (i++): Current value of i is 1, and after applying i++, the value of i becomes 1 ---------------------------------------- يوضّح هذا البرنامج البسيط استخدام عامل الزيادة البادئ وعامل الزيادة اللاحق. يبدأ البرنامج بالتصريح عن المتغيّر i من النوع int وإسناد القيمة 1 إليه. تعمل العبارة في السطر 13 على إظهار قيمتين، الأولى هي القيمة الحاليّة للمتغيّر i وتساوي 1، والقيمة الثانيّة هي قيمة المتغيّر i مضافًا إليها 1 باستخدام عامل الزيادة البادئ ++i أي هي القيمة 2، إذًا يقوم هذا العامل بزيادة قيمة المتغيّر i بمقدار 1 قبل تمرير القيمة النهائيّة إلى التابع WriteLine لذلك نحصل على الخرج: Current value of i is 1, and after applying ++i, the value of i becomes 2 ولكن على النقيض من ذلك، نلاحظ أنّ العبارة الموجودة في السطر 20 تعمل على إظهار قيمتين أيضًا، الأولى هي القيمة الحالية للمتغيّر i وتساوي 1 (أعدنا إسناد القيمة 1 للمتغيّر i في السطر 17)، والقيمة الثانيّة هي قيمة المتغيّر i مضافًا إليها 1 باستخدام الزيادة اللاحق i++ ولكن لن تمرَّر القيمة 2 هذه المرّة إلى التابع WriteLine. والسبب في ذلك أنّ البرنامج سيعمل على تمرير قيمة i الأصلية (القيمة 1) ثمّ يطبّق بعد ذلك عامل الزيادة اللاحق. وهذا هو سبب الحصول على الخرج التالي: Current value of i is 1, and after applying i++, the value of i becomes 1 لعلّ هذا السلوك يُسبّب بعض الإرباك للمبرمجين الجدد في سي شارب، وعلى أيّة حال أنصح بتجنّب تمرير القيمة إلى التوابع عمومًا بهذا الأسلوب. إذا احتجت لزيادة (أو إنقاص) قيمة متغيّر ما قبل تمرير لأحد التوابع فاعمل على ذلك ضمن سطر منفصل قبل استدعاء هذا التابع وأرح نفسك. في الحقيقة يُطبّق نفس المفهوم السابق بالنسبة لعامليّ الإنقاص البادئ والإنقاص اللاحق. ملاحظة: انظر إلى طريقة التنسيق الجديدة التي استخدمتها في السطر 13: Console.WriteLine("Current value of i is {0}, and after applying ++i, the value of i becomes {1}", i, ++i); مرّرت إلى التابع WriteLine ثلاثة وسائط: الأوّل هو النص التنسيقي وقد حُجز ضمنه مكانين مخصّصين لقيمتين سأمرّرهما لاحقًا لهذا التابع، هذان المكانان على الشكل {0} و {1}. الوسيط الثاني هو المتغيّر i، والوسيط الثالث هو ++i. سيعمل البرنامج على وضع القيمة الممرّرة للتابع WriteLine والتي تلي النص التنسيقي مباشرةً (في حالتنا هذه قيمة i) في المكان {0}، أمّا المكان {1} فسيُوضع ضمنه القيمة التالية وهي ++i. ينطبق نفس الكلام تمامًا على العبارة الموجودة في السطر 20. كما يحتوي السطران 14 و21 على أسلوب جميل لطباعة سطر فاصل في خرج البرنامج بغرض توضيحه. أنشأنا كائنًا من النوع string باستخدام العامل new ومرّرنا لبانيته وسيطين: الأوّل المحرف '-' من نوع char والثاني القيمة 40: new string('-', 40) سيولّد ذلك نصّا يحتوي على 40 محرف '-' مكرّر (لاحظ علامتي الاقتباس المفردتين ' ')، يمرَّر هذا النص بعد ذلك إلى التابع WriteLine. لا تقلق إن بدا هذا الكلام غير مفهومًا الآن، فسنتحدّث عن الكائنات فيما بعد. فهم عامل النفي المنطقي وعامل التحويل بين الأنواع أنشئ مشروعًا جديدًا من النوع Console Application سمّه UnaryOperatorsTest2 ثم استبدل محتويات الملف Program.cs بالشيفرة التالية: 1 using System; 2 3 4 namespace UnaryOperatorsTest2 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 bool b = true; 11 double d = 8.9; 12 int i; 13 14 Console.WriteLine("b = {0}, !b = {1}", b, !b); 15 16 i = (int)d; 17 Console.WriteLine("d = {0}, after applying casting to (int), i = {1}", d, i); 18 } 19 } 20 } نفّذ البرنامج باستخدام Ctrl+F5 لتحصل على الخرج التالي: b = True, !b = False d = 8.9, after applying casting to (int), i = 8 استخدمنا في هذا البرنامج المتغير b من النوع bool وهو نوع منطقيّ تحمل المتغيّرات المصرّح عنها بواسطته إحدى قيمتين true أو false. أسندنا للمتغيّر b القيمة true عند التصريح عنه في السطر 10، ثمّ عرضنا للمستخدم قيمة b الأصليّة وقيمته بعد تطبيق عامل النفي المنطقي عليه b! لنحصل على الخرج التالي: b = True, !b = False يعكس هذا العامل الحالة المنطقيّة، فإذا كانت true تصبح false، أمّا إذا كانت false فتصبح true. ولكن إذا لاحظت أنّ الخرج يُظهر القيمتين المنطقيتين true و false بحرفين كبيرين في بداية كل منهما: True و False. السبب في ذلك أن التابع WriteLine في السطر 14 يعمل بشكل ضمني على استدعاء التابع ToString لكل من الوسيطين الممرّرين له، أي الوسيطين b و b! فيحصل بذلك على التمثيل النصّي للقيمة المنطقيّة الموجودة في كلّ منهما، والذي يبدأ بحرف طباعي كبير. جرّب استبدال العبارة البرمجيّة في السطر 14 بالعبارة التالية: Console.WriteLine("b = {0}, !b = {1}", b.ToString(), (!b).ToString()); التعديل الذي أجريناه في السطر السابق هو استدعاء التابع ToString بشكل صريح لكلّ وسيط قبل تمريره إلى التابع WriteLine. ستحصل بذلك على نفس الخرج دون أيّ تغيير. بالنسبة لعمليّة التحويل بين الأنواع فقد أجريناها بين المتغيّر d من النوع double (السطر 11) والمتغيّر i من النوع int (السطر 12)، حيث سنحوّل القيمة ذات الفاصلة العشرية 8.9 الموجودة في d إلى قيمة صحيحة بدون فاصلة ونخزّنها ضمن i. تجري عملية التحويل هذه في السطر 16 على الشكل التالي: i = (int)d; لاحظ أنّ القوسين المحيطين بـ int ضروريين. إذا حاولت إزالة عامل التحويل (int) من العبارة السابقة وحاولت تنفيذ البرنامج فستحصل على الخطأ التالي: CS0266 Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?) يُشير هذا الخطأ إلى عدم إمكانيّة إسناد قيمة متغيّر من النوع double إلى متغيّر من النوع int مباشرةً بدون تحويل لأنّ ذلك سيؤدّي إلى ضياع في البيانات (ستضيع القيمة 0.9). يقترح عليك هذا الخطأ استخدام التحويل بين الأنواع cast في الجزء الأخير من الرسالة. أعد وضع عامل التحويل (int) أمام المتغيّر d ونفّذ البرنامج لتحصل في الخرج على ما يلي: d = 8.9, after applying casting to (int), i = 8 انظر كيف أصبحت قيمة i تساوي 8. في الواقع سيصادفنا عامل التحويل كثيرًا في هذه السلسلة. العوامل الثنائية تشتمل هذه العوامل على معظم العوامل الموجودة في سي شارب ولها العديد من الأصناف، تحتاج هذه العوامل إلى وجود مُعاملَين operands على طرفيها لكل تعمل، يلخّص الجدول التالي أهم هذه العوامل مع التصنيف الذي تقع ضمنه. العامل الوصف الاستخدام التصنيف + عملية الجمع العددي x + y عوامل - عملية الطرح العددي x - y حسابيّة * عملية الضرب العددي x * y / عملية القسمة العددية (إذا كان كل من المعاملين من نوع صحيح فسيكون ناتج القسمة صحيحًا بدون فاصلة، حيث تُهمل الأجزاء العشرية في حال وجودها). x / y % عمليّة باقي القسمة x % y > عامل اختبار "أصغر من" يُرجع القيمة true إذا كان المُعامل الأيسر أصغر من الأيمن، وإلّا يُرجع false. x < y عوامل مقارنة < عامل اختبار "أكبر من" يُرجع القيمة true إذا كان المُعامل الأيسر أكبر من الأيمن، وإلّا يُرجع false. x > y => عامل اختبار "أصغر من أو يساوي" يُرجع القيمة true إذا كان المُعامل الأيسر أصغر من أو يساوي الأيمن، وإلّا يُرجع false. x <= y =< عامل اختبار "أكبر من أو يساوي" يُرجع القيمة true إذا كان المُعامل الأيسر أكبر من أو يساوي الأيمن، وإلّا يُرجع false. x >= y == عامل اختبار "المساواة" بين قيمتين، يُرجع true إذا كانت القيمتين متساويتين وإلّا يُرجع false. x == y عوامل اختبار المساواة =! عامل اختبار "عدم المساواة" بين قيمتين، يُرجع true إذا كانت القيمتين غير متساويتين وإلّا يُرجع false. x != y && تطبيق منطق AND على قيمتين (أو تعبيرين) منطقيين. x && y العوامل || تطبيق منطق OR على قيمتين (أو تعبيرين) منطقيين. x || y الشرطية = عامل الإسناد للقيمة (أو التعبير) الموجودة في اليمين إلى المتغيّر الموجود في اليسار. x = y عوامل إسناد =+ عامل الجمع ثم الإسناد. x += y =- عامل الطرح ثم الإسناد. x -= y =* عامل الضرب ثم الإسناد. x *= y =/ عامل القسمة ثم الإسناد. x /= y =% عامل باقي القسمة ثم الإسناد. x %= y فهم العوامل الحسابية تُعتبر هذه العوامل بسيطة وواضحة وهي مشتركة بين جميع لغات البرمجة. على أيّة حال إليك برنامجًا بسيطًا يتعامل معها ويوضّح وظائفها. 1 using System; 2 3 namespace ArithmeticOperators 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 int x, y; 10 string str_x, str_y; 11 12 //input operands. 13 Console.Write("Input left operand (x) : "); 14 str_x = Console.ReadLine(); 15 16 Console.Write("Input right operand (y) : "); 17 str_y = Console.ReadLine(); 18 19 //convert each operand to integer representative. 20 x = int.Parse(str_x); 21 y = int.Parse(str_y); 22 23 24 Console.WriteLine(); 25 26 //perform arithmetic calculations and display results. 27 Console.WriteLine("x + y = {0}", x + y); 28 Console.WriteLine("x - y = {0}", x - y); 29 Console.WriteLine("x * y = {0}", x * y); 30 Console.WriteLine("x / y = {0}", x / y); 31 Console.WriteLine("x % y = {0}", x % y); 32 33 } 34 } 35 } نفّذ البرنامج باستخدام Ctrl+F5. سيطلب منك البرنامج إدخال المُعامل الأيسر left operand، ثم المُعامل الأيمن right operand، وبعدها ينفّذ العمليّات الحسابيّة الأربع عليهما. جرّب إدخال القيمتين 9 و 2 على الترتيب لتحصل على الخرج التالي: Input left operand (x) : 9 Input right operand (y) : 2 x + y = 11 x - y = 7 x * y = 18 x / y = 4 x % y = 1 العمليّات الثلاث الأولى واضحة. بالنسبة لعمليّة القسمة يجب أن يكون الناتج 4.5، ولكن بما أنّ عملية القسمة تجري بين قيمتين صحيحتين فإنّ النتيجة يجب أن تكون صحيحة، وبالتالي يُهمل الجزء العشري 0.5 ويكون الناتج 4 فقط. بالنسبة لعمليّة باقي القسمة x % y فإنّ النتيجة 1 هي باقي قسمة 9 على 2. ملاحظة: إذا لم ترغب بحذف الجزء العشري من ناتج عملية القسمة الصحيحة ودون أن تغيّر أنوع المتغيّرات، يمكنك استخدام عامل التحويل بين الأنواع (T). استبدال العبارة الموجودة في السطر 30 بالعبارة التالية: Console.WriteLine("x / y = {0}", x /(double)y); وضعت عامل التحول (double) قبل المتغيّر y لتحويل قيمته العدديّة إلى قيمة من نوع double (دون المسّ بقيمة y الأصليّة بالطبع)، فعندما يرى البرنامج أنّه يُجري عملية القسمة بين قيمة صحيحة (قيمة x) وقيمة من النوع double فسيعطي الناتج على شكل قيمة من نوع double تُمرّر بدورها إلى التابع WriteLine ليعرض القيمة 4.5 بدلًا من 4. ويمكن فعل نفس الأمر مع المتغيّر x بدلًا من y إذا أحببت. فهم عوامل المقارنة سنتناول عوامل المقارنة > و < و => و =< و == و =! في البرنامج التالي: 1 using System; 2 3 4 namespace RelationalOperators 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 int x, y; 11 string str_x, str_y; 12 13 14 //input operands. 15 Console.Write("Input left operand : "); 16 str_x = Console.ReadLine(); 17 18 Console.Write("Input right operand : "); 19 str_y = Console.ReadLine(); 20 21 //convert each operand to integer representative. 22 x = int.Parse(str_x); 23 y = int.Parse(str_y); 24 25 Console.WriteLine(); 26 27 //perform comparing operations and display results. 28 Console.WriteLine("{0} == {1} evaluates to {2}", x, y, x == y); 29 Console.WriteLine("{0} != {1} evaluates to {2}", x, y, x != y); 30 Console.WriteLine("{0} > {1} evaluates to {2}", x, y, x > y); 31 Console.WriteLine("{0} >= {1} evaluates to {2}", x, y, x >= y); 32 Console.WriteLine("{0} < {1} evaluates to {2}", x, y, x < y); 33 Console.WriteLine("{0} <= {1} evaluates to {2}", x, y, x <= y); 34 } 35 } 36 } نفّذ البرنامج وأدخل القيمتين 3 و 4 على الترتيب لتحصل على الخرج التالي: Input left operand : 3 Input right operand : 4 3 == 4 evaluates to False 3 != 4 evaluates to True 3 > 4 evaluates to False 3 >= 4 evaluates to False 3 < 4 evaluates to True 3 <= 4 evaluates to True تكون نتيجة تنفيذ عوامل المقارنة قيمة منطقية true أو false. جرّب إدخال قيم متنوّعة، كما جرّب إدخال قيمتين متساويتين وانظر إلى الخرج. فهم العوامل الشرطية العاملين الشرطيين && (AND) و || (OR) هما عاملان مهمّان جدًّا ويستخدمان بكثرة في بنى القرار في سي شارب. ولهما وجود في جميع لغات البرمجة. يوضّح البرنامج التالي استخدام هذين العاملين بصورة مبسّطة. 1 using System; 2 3 4 namespace RelationalOperators 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 int a, b, c, d; 11 bool and_operator, or_operator; 12 13 a = 1; 14 b = 2; 15 c = 5; 16 d = 9; 17 18 and_operator = (a > b) && (c <= d); 19 Console.WriteLine("({0} > {1}) && ({2} <= {3}) evaluates to {4}", a, b, c, d, and_operator); 20 21 or_operator = (a > b) || (c <= d); 22 Console.WriteLine("({0} > {1}) || ({2} <= {3}) evaluates to {4}", a, b, c, d, or_operator); 23 } 24 } 25 } لا نستخدم العوامل الشرطيّة بهذا الأسلوب في البرامج الحقيقيّة، ولكنّ هذا الأسلوب مفيد في توضيح آلية عمل العوامل الشرطيّة وتفاعلها مع عوامل المقارنة. نفّذ البرنامج لتحصل على الخرج التالي: (1 > 2) && (5 <= 9) evaluates to False (1 > 2) || (5 <= 9) evaluates to True تفسير هذا الخرج يسير للغاية. لنبدأ بالسطر الأوّل، نتيجة حساب التعبير الأول هو false: (1 > 2) && (5 <= 9) وسبب ذلك هو أنّ نتيجة التعبير (2 < 1) هو false، أمّا نتيجة حساب (9 => 5) هو true وبالتالي سيعمل العامل الشرطي && بالنتيجة على حساب التعبير false && true والذي يعطي بكلّ تأكيد القيمة المنطقية false. بالنسبة للسطر الثاني، وهو التعبير: (1 > 2) || (5 <= 9) والذي يعطي true. والسبب هو أنّ العامل الشرطي || سيعمل على حساب التعبير false || true والذي يعطي القيمة المنطقيّة true. لاحظ استخدام الأقواس على أطراف عوامل المقارنة، يمكن الاستغناء عنها، ولكن لا أنصح بذلك، استخدم الأقواس دومًا حتى ولو لم يكن استخدامها ضروريًا لتوضيح منطق البرنامج، ولكن استخدمها بحكمة. السبب في انتفاء الحاجة إلى استخدام الأقواس في هذا البرنامج، هو أنّ عوامل المقارنة لها أسبقيّة تنفيذ أعلى من العوامل الشرطيّة، لذلك فهي تُقيّم قبل تقييم العوامل الشرطيّة. فهم عوامل الإسناد استخدمنا حتى الآن عامل الإسناد (=). توجد عوامل إسناد أخرى تُسهّل البرمجة في سي شارب وهي =+ و =- و =* و =/ و =%. الأمر بسيط، بالنسبة لعامل الإسناد =+ يمكن توضيح عمله بالشيفرة التالية: int x = 3; x += 5; بعد تنفيذ الشيفرة السابقة ستصبح قيمة x تساوي 8. لأنّ العبارة x += 5 تكافئ تمامًا العبارة x = x + 5 ويمكننا استبدالها بها. يُطبّق نفس الأسلوب تمامًا على العوامل الباقية. فمثلًا انظر إلى الشيفرة التالية: int x = 21; x /= 4; x %= 3; هل تستطيع تخمين قيمة x بعد تنفيذ هذه الشيفرة؟ إذا كانت النتيجة 2 فقد أصبت. السبب في ذلك بسيط. فقد بدأنا بقيمة x تساوي 21 ثم نفّذنا العبارة x /= 4 التي تكافئ العبارة x = x / 4 وهي قسمة صحيحة، لذلك سيحمل x القيمة 5 (بدون فاصلة عشرية). بعد تنفيذ العبارة الأخيرة x %= 3 التي تكافئ العبارة x = x % 3 ستصبح قيمة x تساوي 2 لأنّ باقي قسمة 5 على 3 يساوي 2. وهذا كلّ ما في الأمر. تمارين داعمة تمرين 1 حاول تخمين القيمة المنطقيّة التي ستُطبع على الشاشة باستخدام القلم والورقة فقط: int a = 30; a /= 3; a %= 3; Console.WriteLine(a == 1); تمرين 2 حاول تخمين قيمة f التي ستُطبع على الشاشة باستخدام القلم والورقة فقط: int x; double f; x = 9; f = (double)x / 2; f *= 10; Console.WriteLine("f = {0}", f); الخلاصة لفد تعرّفنا في هذا الدرس على الأنواع المُضمّنة في سي شارب وعلى مجالات كلٍّ منها، وعلى الفرق الأساسي بين أنواع القيمة value types والأنواع المرجعيّة reference types. كما تحدّثنا عن معظم العوامل التي تدعمها سي شارب وتصنيفاتها. وتناولنا بعض الأمثلة التوضيحيّة على استخدامها. سنتحدّث في الدرس التالي عن بنى القرار وتغيير مسار البرنامج وهو موضوع مهم في جميع لغات البرمجة.
  2. تُعتبر الحلقات التكراريّة من البنى المهمّة في لغات البرمجة، حيث نستطيع من خلالها تنفيذ عبارة أو عدّة عبارات برمجيّة لعدد من المرّات. تدعم سي شارب مثل باقي لغات البرمجة نوعين من الحلقات التكراريّة من حيث عدد التكرار، فهناك الحلقات ذات العدد المحدّد من المرّات (حلقة for) والتي نعلم فيها عدد مرّات التكرار بشكل مسبق، والحلقات ذات العدد غير المحدّد من المرّات (حلقة do-while وحلقة while) التي يكون فيها عدد مرّات التكرار غير مُحدّدًا. حلقة for التكرارية يمكن من خلال هذه الحلقة تكرار تنفيذ عبارة برمجيّة أو أكثر عددًا محدّدًا من المرّات، ولهذه الحلقة الشكل العام التالي: for ([init_counter]; [loop_condition]; [counter_expression]) { statement1; statement2; ... } القسم [init_counter] هو قسم التهيئة الذي يتمّ من خلاله تهيئة متغيّر الحلقة بقيمة ابتدائيّة (وغالبًا ما يتمّ التصريح عنه في هذا القسم أيضًا)، يسمّى متغيّر الحلقة أيضًا بعدّاد الحلقة loop counter، أمّا القسم [loop_condition] فيمثّل شرط التكرار أو الاستمرار للحلقة، فهو تعبير مقارنة يعطي true أو false بحيث تستمرّ الحلقة بالتكرار طالما كان هذا الشرط محقّقًا (يعطي true). القسم الأخير [counter_expression] ويتمّ فيه عادةً إجراء عملية حسابية على متغيّر الحلقة وغالبًا ما تكون هذه العمليّة هي زيادة متغيّر الحلقة بمقدار واحد. انظر الشيفرة البسيطة التالية التي تعمل على تنفيذ العبارة التي تحوي التابع WriteLine ثلاث مرّات: for (int i = 0; i < 3; i++) { Console.WriteLine("i = {0}", i); } عند تنفيذ الشيفرة السابقة ستحصل على الخرج التالي: i = 0 i = 1 i = 2 لاحظ أنّنا صرّحنا عن المتغيّر i من النوع int وأسندنا إليها القيمة 0 في قسم التهيئة، وبالنسبة لشرط الاستمرار للحلقة i < 3 فمن الواضح أنّ الحلقة ستستمرّ بالتكرار طالما كانت قيمة i أصغر تمامًا من 3. أمّا بالنسبة للقسم الأخير فنعمل على زيادة قيمة متغيّر الحلقة i بمقدار 1 في كلّ دورة عن طريق عامل الزيادة اللاحق ++i. آلية عمل هذه الحلقة بسيطة: عندما يصل تنفيذ البرنامج إلى حلقة for يتمّ التصريح عن المتغيّر i وإسناد القيمة 0 إليه. يختبر البرنامج شرط استمرار الحلقة i < 3 فإذا كان true يبدأ بتنفيذ العبارات البرمجيّة الموجودة ضمن حاضنة for. وإلّا يخرج فورًا من الحلقة. بعد الانتهاء من تنفيذ العبارات ضمن حاضنة for، ينتقل البرنامج إلى التعبير ++i ليزيد قيمة i بمقدار 1. تتكرّر نفس الخطوتين 2 و 3. سيتكرّر في هذا المثال البسيط تنفيذ العبارة الموجودة في الحاضنة ثلاث مرّات لأنّ العدّ يبدأ من الصفر (قيمة i الابتدائيّة تساوي الصفر). لنتناول الآن برنامجًا عمليًّا وظيفته إيجاد مجموع سلسلة من الأعداد المتتالية. أنشئ برنامجًا جديدًا اسمه Lesson04_1 ثمّ استبدل محتويات الملف Program.cs بالشيفرة التالية: 1 using System; 2 3 namespace Lesson04_1 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 int n, sum = 0; 10 string str_n; 11 12 Console.WriteLine("This Program calculates the series: sum = 1 + 2 + 3 + ... + n"); 13 Console.Write("Input 'n' please: "); 14 str_n = Console.ReadLine(); 15 16 n = int.Parse(str_n); 17 18 for (int i = 1; i <= n; i++) 19 { 20 sum += i; 21 } 22 23 Console.WriteLine("sum = {0}", sum); 24 } 25 } 26 } يعمل البرنامج السابق على جمع الأعداد من 1 حتى القيمة المدخلة n. أي سيحسب برنامجنا مجموع السلسلة: 1 + 2 + 3 + … + n. لاحظ القيمة الابتدائيّة للمتغيّر i (تساوي 1) وشرط استمرار الحلقة i <= n في السطر 18. تذكّر أنّ العبارة الموجودة في السطر 20 تُكافئ العبارة sum = sum + i. نفّذ البرنامج وجرّب إدخال قيم مختلفة للمتغيّر n لتحصل على المجاميع الموافقة. ملاحظة: المتغيّر i في البرنامج السابق مرئي فقط ضمن الحلقة التكراريّة ولا وجود له خارجها، يعرف هذا بمجال الرؤية للمتغيّر variable scope. ستؤدّي محاولة الوصول للمتغيّر i خارج الحلقة إلى خطأ أثناء بناء البرنامج. سنكتب الآن برنامجًا آخرًا لحساب مجموع السلسلة: 2 + 4 + 6 + 8 + … + n. لن يختلف البرنامج في هذا المثال عن البرنامج Lesson04_1 باستثناء أنّنا سنجمع الأعداد الزوجية فقط. إليك البرنامج كما سيبدو: 1 using System; 2 3 namespace Lesson04_2 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 int n, sum = 0; 10 string str_n; 11 12 Console.WriteLine("This Program calculates the series: sum = 2 + 4 + 6 + ... + n"); 13 Console.Write("Input 'n' please: "); 14 str_n = Console.ReadLine(); 15 16 n = int.Parse(str_n); 17 18 for(int i = 0; i <= n; i += 2) 19 { 20 sum += i; 21 } 22 23 Console.WriteLine("sum = {0}", sum); 24 } 25 } 26 } لاحظ كيف نزيد قيمة المتغيّر i في كلّ تكرار للحلقة for بمقدار 2 باستخدام التعبير i += 2 (السطر 18)، وبالتالي نتفادى جمع الأعداد الفردية (لاحظ أنّ قيمة i بدأت من الصفر). فيما عدا ذلك يبدو هذا البرنامج مطابقًا لبنية البرنامج Lesson04_1. حلقة while التكرارية لهذه الحلقة التكراريّة الشكل العام التالي: while (loop_condition) { statement1; statement2; ... } ستتكرّر العبارات البرمجيّة الموجودة ضمن حاضنة while طالما كان الشرط loop_condition محقّقًا (أي true) وبمجرّد أن يصبح الشرط loop_condition غير محقّق تتوقّف الحلقة عن التكرار. سنعدّل البرنامج Lesson04_1 السابق لكي يسمح باستخدام الحلقة while. أنشئ مشروعًا جديدًا وسمّه Lesson04_3 ثم استبدل محتويات Program.cs بما يلي: 1 using System; 2 3 namespace Lesson04_3 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 int n, sum = 0, i = 1; 10 string str_n; 11 12 Console.WriteLine("This Program calculates the series: sum = 1 + 2 + 3 + ... + n"); 13 Console.Write("Input 'n' please: "); 14 str_n = Console.ReadLine(); 15 16 n = int.Parse(str_n); 17 18 while (i <= n) 19 { 20 sum += i; 21 22 i++; 23 } 24 25 Console.WriteLine("sum = {0}", sum); 26 } 27 } 28 } صرّحنا عن المتغيّر i وأسندنا له القيمة 1 في السطر 9 والذي سيمثّل متغيّر حلقة while. استبدلنا حلقة for بحلقة while في السطر 18 مع ملاحظة أنّ شرط استمرار الحلقة i <= 5 بقي دون تعديل. لاحظ العبارة المهمّة في السطر 22 والتي تحوي التعبير ++i الذي سيزيد قيمة i بمقدار واحد في كلّ دورة. إنّ إغفال هذه العبارة سيؤدّي إلى الدخول في حلقة لا نهائيّة، لأنّ شرط الاستمرار في هذه الحالة لن يعطي false أبدًا لأنّ قيمة i لن تتغيّر. نفّذ البرنامج وأدخل قيم مختلفة للمتغيّر n لاختبار البرنامج. جرّب الآن إدخال القيمة 0 للمتغيّر n ستحصل في الخرج على المجموع sum = 0 وهذا منطقيّ. إذ أنّنا نخبر البرنامج بأنّنا لا نريد جمع أي عدد. سبب الحصول على هذا الخرج في الواقع هو أنّ البرنامج أثناء التنفيذ لن يدخل إلى حلقة while مطلقًا لأنّ شرط الاستمرار i <= n سيكون غير محقّقًا منذ البداية (تذكّر أنّ قيمة i الابتدائيّة هي 1). حلقة do-while التكرارية لهذه الحلقة الشكل العام التالي: do { statement1; statement2; ... } while (loop_condition) وهي تشبه الحلقة while باستثناء أنّ شرط استمرار الحلقة loop_condition يجري اختباره في نهايتها وليس في بدايتها كما هو الحال مع حلقة while. قد لا يبدو هذا الأمر مهمًّا في البداية ولكنّه في الحقيقة عكس ذلك تمامًا. لفهم الفرق أنشئ مشروعًا جديدًا وسمّه Lesson04_04 ثمّ استبدل الشيفرة الموجودة في Program.cs بالشيفرة التالية: 1 using System; 2 3 namespace Lesson04_4 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 int n, sum = 0, i = 1; 10 string str_n; 11 12 Console.WriteLine("This Program calculates the series: sum = 1 + 2 + 3 + ... + n"); 13 Console.Write("Input 'n' please: "); 14 str_n = Console.ReadLine(); 15 16 n = int.Parse(str_n); 17 18 Do 19 { 20 sum += i; 21 22 i++; 23 } 24 while (i <= n); 25 26 Console.WriteLine("sum = {0}", sum); 27 } 28 } 29 } لا يختلف هذا البرنامج عن سابقيه في حساب مجموع السلسلة 1 + 2 + 3 + … + n، نفّذ البرنامج وأدخل القيمة 0 للمتغيّر n ستحصل في الخرج على المجموع sum = 1 وهذا خطأ بالطبع! السبب في ذلك أنّ اختبار شرط الاستمرار في حلقة do-while يجري بعد انتهاء الحلقة من تنفيذ أوّل دورة لها، حيث تؤدّي هذه الدورة إلى جعل قيمة المتغيّر sum تساوي 1 وقيمة i تساوي 2، وبعد ذلك يأتي اختبار الشرط i <= n والذي سيعطي false بالطبع وتتوقف الحلقة عن التكرار ولكن بعد فوات الأوان. في حلقة while (وحتى في حلقة for) لم نواجه هذه المشكلة لأنّ شرط استمرارها يجري اختباره في بداية الحلقة وقبل تنفيذ أي دورة تكراريّة. تمارين داعمة تمرين 1 اكتب برنامجًا يطبع الأعداد من 1 حتى 100 على الشاشة باستثناء الأعداد من مضاعفات العدد 5 أي على الشكل التالي: 1, 2, 3, 4, 6, 7, 8, 9, 11, … , 14, 16, … تلميح: ستحتاج في هذا التمرين إلى استخدام بنية if ضمن حلقة for واختبار قيمة التعبير المنطقي i % 5 == 0 على افتراض أنّ i هو عدّاد الحلقة. تمرين 2 اكتب برنامجًا يطلب من المستخدم إدخال عدد صحيح موجب ثمّ يوجد مضروب هذا عدد (قيمة العاملي له). فإذا أدخل عددًا سالبًا يجب على البرنامج أن ينبّه المستخدم على ذلك ويُنهي التنفيذ. تلميح: تذكّر أنّ مضروب عدد يُعبّر عن الجداءات للقيم المتناقصة لهذا العدد فمثلًا لإيجاد مضروب 5 (!5) نكتب: 5! = 5 * 4 * 3 * 2 * 1 تذكّر أيضًا أنّ !1 =1 و !0 = 1. الخلاصة تحدثنا في هذا الدرس عن الحلقات التكراريّة بأنواعها المختلفة. تدعم سي شارب عدة حلقات تكراريّة تُعتبر حلقة for من أهمّها. في الحقيقة توجد حلقة تكراريّة أخرى لم نتحدّث عنها في هذا الدرس، وهي حلقة foreach، وهي حلقة مفيدة جدًّا أجلّت الحديث عنها إلى أن نتعرّف على المجموعات Collections بأنواعها ونتعلّم التعامل معها.
  3. تعتبر العبارات الشرطية في البرنامج من الأمور الأساسيّة في البرمجة كما هو معلوم. تمتلك لغة سي شارب نوعين من العبارات الشرطية وهما: بنية if-else وبنية switch-case. العبارة الشرطية if-else وهي بنية مألوفة في معظم لغات البرمجة، تشبه هذه البنية في تشكيلها تلك الموجودة في لغات أخرى مثل ++C و Java. تمتلك هذه البنية ثلاثة أشكال سنتحدّث عنها تباعًا. الشكل الأول لبنية if الشكل الأبسط لبنية if هي: if ([condition]) { statement1; statement2; ... } إذا كان تقييم evaluate الشرط [condition] يعطينا true (أي تحقّق الشرط) عندها ستُفّذ العبارات البرمجيّة الموجودة ضمن الحاضنة {}، وإلّا (أي لم يتحقّق الشرط) فلن يُنفّذ أيّ منها. أنشئ مشروعًا جديدًا سمّه Lesson03_1 واستبدل محتويات الملف Program.cs بالبرنامج البسيط التالي الذي يعمل على مقارنة القيمة المدخلة من المستخدم مع العدد 5 ويُظهر الخرج المناسب: 1 using System; 2 3 namespace Lesson03_1 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 double x; 10 string str_x; 11 12 Console.Write("Input a number: "); 13 str_x = Console.ReadLine(); 14 15 x = double.Parse(str_x); 16 17 if(x > 5) 18 { 19 Console.WriteLine("The value {0} is greater than 5", x); 20 } 21 22 Console.WriteLine("Goodbye!"); 23 } 24 } 25 } جرّب تنفيذ هذا البرنامج باستخدام Ctrl+F5 (أو من القائمة Debug > Start Without Debugging). سيطلب منك البرنامج إدخال قيمة عدديّة، أدخل العدد 6، سيعرض البرنامج الخرج التالي: The value 6 is greater than 5 Goodbye! أعد تنفيذ البرنامج وأدخل هذه المرّة القيمة 3 لتحصل على الخرج التالي: Goodbye! لاحظ بأنّ خرج البرنامج قد اختلف باختلاف القيم المدخلة، أي أنّ هناك اختلاف في العبارات البرمجيّة التي تمّ تنفيذها في كلّ مرّة. يعود سبب ذلك إلى البنية if الموجودة بين السطرين 17 و 20. يختبر الشرط الموجود بعد كلمة if في السطر 17 فيما إذا كانت قيمة المتغيّر x أكبر تمامًا من 5. فإذا كانت نتيجة تقييم التعبير x > 5 تساوي true فهذا يعني أنّ الشرط قد تحقّق وبالتالي تنفّذ جميع العبارات البرمجيّة الموجودة في الحاضنة (بين السطرين 18 و 20). أمّا إذا كانت نتيجة تقييم التعبير x > 5 تساوي false فعندها سيتجاوز تنفيذ البرنامج البنية if إلى العبارات التي تأتي بعد السطر 20. الشكل الثاني لبنية if هذا الشكل للعبارة الشرطية if مفيد أيضًا، ويُستخدم عندما نريد الاختيار بين مجموعتين من العبارات البرمجيّة، والشكل العام له: if ([condition]) { statement1; statement2; ... } else { Statement3; Statement4; ... } لقد أضفنا القسم else مع حاضنته. المنطق هنا بسيط يمكننا قراءته بالشكل التالي: "إذا تحقق الشرط [condition] عندها تنفّذ الحاضنة الموجودة بعد if مباشرةً، وإلّا يتم تنفيذ الحاضنة الموجودة بعد else مباشرةً" لكي نتعرّف على كيفيّة التعامل مع هذا الشكل، أنشئ مشروعًا جديدًا سمّه Lesson03_2 وانسخ الشيفرة التالية إلى الملف Program.cs: 1 using System; 2 3 namespace Lesson03_2 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 double x; 10 string str_x; 11 12 Console.Write("Input a number: "); 13 str_x = Console.ReadLine(); 14 15 x = double.Parse(str_x); 16 17 if (x > 5) 18 { 19 Console.WriteLine("The value {0} is greater than 5", x); 20 } 21 else 22 { 23 Console.WriteLine("The value {0} is smaller than or equals 5", x); 24 } 25 26 Console.WriteLine("Goodbye!"); 27 } 28 } 29 } هذا البرنامج مطابق للبرنامج الذي رأيناه قبل قليل باستثناء القسم else مع حاضنته. يسلك هذا البرنامج نفس السلوك الذي يسلكه البرنامج السابق باستثناء أنّه لو أدخل المستخدم قيمة مثل 3 سيعمل البرنامج على طباعة الخرج التالي: The value 3 is smaller than or equals 5 Goodbye! لاحظ أنّ البرنامج Lesson03_1 كان يطبع العبارة !Goodbye فقط عند إدخال القيمة 3. السبب في ظهور الخرج الجديد هو وجود القسم else في بنية if السابقة، فعندما يُقيّم الشرط x > 5 في السطر 17 وتكون نتيجة تقييمه false سينتقل البرنامج فورًا إلى تنفيذ العبارات البرمجيّة الموجودة ضمن حاضنة else وهذا هو سبب ظهور هذا الخرج. العيب الوحيد في هذا البرنامج أنّه لا يستطيع التمييز بين الحالة التي تكون فيها القيمة المدخلة تساوي 5 وبين الحالة التي تكون فيها أصغر تمامًا من 5، ففي كلّ من هاتين الحالتين يعرض البرنامج نفس الخرج عن طريق تنفيذ العبارة الموجودة في السطر 23. ملاحظة: في حال كانت أيّة حاضنة تحوي عبارة برمجيّة واحد فقط، فعندها يمكن عدم استخدام قوسي الحاضنة {} مع أنّني أفضّل استخدامهما لجعل البرنامج أكثر وضوحًا. الشكل الثالث لبنية if وهو الشكل الأكثر شمولًا وفيه نستخدم القسم else if على الصورة التالية: if ([condition]) { statement1; statement2; ... } else if ([condition1]) { Statement3; Statement4; ... } else if ([condition2]) { Statement3; Statement4; ... } ... else { Statement3; Statement4; ... } يمكننا قراءة المنطق هنا على الشكل التالي: "إذا تحقّق الشرط [condition] عندها تنفّذ الحاضنة الموجودة بعد if مباشرةً، وإلّا إذا (else if) تحقّق الشرط [condition1] يتم تنفيذ الحاضنة الموجودة بعد else if الأولى مباشرةً، وإلّا إذا تحقّق الشرط [condition2] يتم تنفيذ الحاضنة الموجودة بعد else if الثانية مباشرةً، وإلّا (else) يتم تنفيذ الحاضنة الموجودة بعد else مباشرةً" نلاحظ أنّه يمكننا استخدام أقسام else if بقدر ما نريد، ولكن يمكن استخدام قسم else وحيد. ونلاحظ أيضًا أنّه بالنتيجة ستنفّذ مجموعة واحدة فقط ضمن حاضنة ما. وواضح أيضًا أنّ أقسام else if و else هي أقسام اختياريّة ووجودها غير مرتبط ببعضها، ولكن إذا حوت بنية if قسم else if فيجب أي يكون القسم else (في حال وجوده) هو القسم الأخير. لكي نثبّت هذا المفهوم بشكل جيّد انظر البرنامج Lesson03_3 التالي: 1 using System; 2 3 namespace Lesson03_3 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 double x; 10 string str_x; 11 12 Console.Write("Input a number: "); 13 str_x = Console.ReadLine(); 14 15 x = double.Parse(str_x); 16 17 if (x > 5) 18 { 19 Console.WriteLine("The value {0} is greater than 5", x); 20 } 21 else if (x == 5) 22 { 23 Console.WriteLine("The value {0} is equals 5", x); 24 } 25 else 26 { 27 Console.WriteLine("The value {0} is smaller than 5", x); 28 } 29 30 Console.WriteLine("Goodbye!"); 31 } 32 } 33 } يشبه هذا البرنامج سابقيه إلى حدٍّ بعيد، فهو يقارن القيمة المدخلة مع العدد 5 ويعرض رسالة مناسبة نتيجة عملية المقارنة. الشيء الجديد هنا هو التمييز بين الحالة التي تكون فيها القيمة المدخلة تساوي العدد 5 والحالة التي تكون فيها أصغر من العدد 5. قمنا بذلك من خلال إضافة القسم else if جديد يختبر حالة المساواة مع العدد 5. الآن أصبح منطق البرنامج كالتالي: "إذا كانت القيمة المدخلة أكبر تمامًا من 5 (السطر 17) عندها تُنفّذ العبارة الموجودة في السطر 19، وإلّا إذا كانت القيمة المدخلة تساوي 5 (السطر 21) عندها تُنفّذ العبارة الموجودة في السطر 23، وإلّا ستكون القيمة المدخلة أصغر من 5 حتمًا، وتُنفَّذ العبارة الموجودة في السطر 27." العبارة الشرطية switch-case تفيد هذه البنية في الاختيار من بين عدّة حالات منفصلة. لهذه البنية الشكل العام التالي: switch(expression) { case [A]: [statements] break; case [B]: [statements] break; ... [default:] [statements] break; } القسم الأخير default هو قسم اختياري، كما يجب أن يكون هناك قسم case واحد على الأقل. إليك الآن البرنامج Lesson03_4 لفهم كيفيّة استخدام هذه البنية: 1 using System; 2 3 namespace Lesson03_4 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 double x, y; 10 string str_x, str_y, operation; 11 12 Console.Write("Input first number: "); 13 str_x = Console.ReadLine(); 14 15 Console.Write("Input second number: "); 16 str_y = Console.ReadLine(); 17 18 Console.Write("Choose operation (+, -, *, /): "); 19 operation = Console.ReadLine(); 20 21 x = double.Parse(str_x); 22 y = double.Parse(str_y); 23 24 switch (operation) 25 { 26 case "+": 27 Console.WriteLine("{0} + {1} = {2}", x, y, x + y); 28 break; 29 case "-": 30 Console.WriteLine("{0} - {1} = {2}", x, y, x - y); 31 break; 32 case "*": 33 Console.WriteLine("{0} * {1} = {2}", x, y, x * y); 34 break; 35 case "/": 36 Console.WriteLine("{0} / {1} = {2}", x, y, x / y); 37 break; 38 default: 39 Console.WriteLine("Unsupported operation."); 40 break; 41 } 42 } 43 } 44 } البرنامج السابق عبارة عن برنامج آلة حاسبة بسيطة تدعم العمليات الحسابية الأربع: الجمع والطرح والضرب والقسمة. يطلب البرنامج من المستخدم إدخال قيمتين عدديّتين، بعد ذلك يطلب اختيار العمليّة الحسابيّة المراد إجراؤها على هاتين القيمتين (+ ، - ، * ، /) وتخزين العمليّة المختارة ضمن المتغيّر النصّي operation وذلك في السطر 19. تعمل البنية switch في السطر 24 على مقارنة قيمة المتغيّر النصيّ operation مع القيم الموجودة في أقسام case (الأسطر 26 و 29 و 32 و 35) فإذا طابقت القيمة الموجودة في operation إحدى تلك القيم، فإنّ العبارات البرمجيّة الموجودة ضمن هذا القسم سيتمّ تنفيذها. أمّا إذا لم يحدث مثل هذا التطابق، فستنفّذ العبارات البرمجيّة الموجودة في القسم الاختياري default والتي ستخبر المستخدم (في هذا المثال) بأنّ العمليّة الحسابيّة التي يرغبها لا يدعمها البرنامج. نستفيد من القسم default في تنفيذ عبارات برمجيّة في حال لم يحدث التطابق مع أيّ قسم case سابق. كما نلاحظ أنّ العبارة break الموجودة في كلّ قسم من أقسام case بالإضافة إلى قسم default هي عبارة ضرورية وتؤدّي إلى انتقال تنفيذ البرنامج إلى خارج بنية switch أي إلى السطر 42. جرّب تنفيذ البرنامج وإدخال قيم متنوّعة بالإضافة إلى تجريب العمليات الحسابيّة الأربع. جرّب إدخال عامل باقي القسمة مثلًا (%) وانظر كيف سيجيب البرنامج بالرسالة Unsupported operation. تمارين داعمة تمرين 1 في البرنامج Lesson03_4 السابق إذا أدخل المستخدم القيمة 0 للعدد الثاني، ثم اختار عمليّة القسمة ( / ) سيؤدّي ذلك إلى القسمة على صفر، وهذا يسبّب خطًأ أثناء التنفيذ runtime error يؤدّي إلى رمي استثناء وتوقّف البرنامج عن العمل. أجرِ تعديلًا على البرنامج ليأخذ هذا الأمر بالحسبان. (تلميح: أضف شرط if ضمن قسم case الموافق للعمليّة ( / ) لاختبار قيمة المتغيّر y فيما إذا كانت تساوي الصفر أم لا). تمرين 2 اكتب برنامجًا يطلب من المستخدم إدخال درجة الحرارة الحاليّة. فإذا كانت درجة الحرارة أقل من 4 مئوية يعرض البرنامج الرسالة "Very Cold". أمّا إذا كانت درجة الحرارة بين 4 وأقل من 10 مئويّة يعرض الرسالة "Cold". وفي حال كانت درجة الحرارة بين 10 وأقل من 30 مئويّة يعرض الرسالة "Normal". أمّا إذا كانت درجة الحرارة 30 فما فوق فيعرض البرنامج الرسالة "Hot". الخلاصة تعلّمنا في هذا الدرس مبادئ التعامل مع العبارات الشرطية والحاجة الماسّة إليها في اتخاذ القرارات المناسبة في البرنامج. تعرّفنا على العبارة الشرطية if-else وأشكالها المفيدة، كما تعرّفنا أيضًا على بنية الاختيار swicth-case. في مجال البرمجة من غير الممكن في الواقع أن يخلو أيّ برنامج فعليّ من وجود عبارة شرطية if واحدة على الأقل.