تكرّر حلقة while جسمها ما دام الشرط صحيحًا. استخدمها حين لا تعرف مسبقًا عدد التكرارات التي تحتاجها: استمر حتى يبلغ رصيد هدفًا، أو تفرغ طابور، أو تنفد المدخلات.
المخرجات:
Year 1: 1070.00
Year 2: 1144.90
Year 3: 1225.04
Year 4: 1310.80
Year 5: 1402.55
Year 6: 1500.73
Goal reached after 6 years
يُفحص الشرط قبل كل تكرار، بما في ذلك الأول. لو كانت savings قد بلغت الهدف أصلًا لما نُفّذ الجسم أبدًا ولطبع البرنامج "after 0 years". تعتمد الحلقة على أن يغيّر الجسم شيئًا يقرؤه الشرط؛ هنا تنمو savings كل سنة حتى تصبح savings < goal خاطئة.
do while: التنفيذ مرة واحدة على الأقل
تنقل حلقة do while الاختبار إلى النهاية، فيُنفَّذ الجسم مرة واحدة على الأقل دائمًا:
المخرجات:
Attempt 1: got 7
Attempt 2: got 4
Attempt 3: got 1
Done after 3 attempts
القيمة الأولى لـ code لا توجد إلا بعد تنفيذ الجسم مرة، وهذا بالضبط حين تناسب do while. تفصيلان في الصياغة يوقعان الناس:
- الفاصلة المنقوطة بعد
while (code != 1)إلزامية. حذفها خطأ ترجمة. - يجب التصريح بالمتغيّرات المستخدمة في الشرط قبل
do. المتغيّر المصرّح به داخل الأقواس يكون خارج النطاق حين يُنفَّذ الشرط، فلا تُترجمdo { int code = ...; } while (code != 1);.
الحلقة نفسها مكتوبة بـ while تحتاج إما إلى تكرار الاستدعاء الأول قبل الحلقة أو إلى قيمة ابتدائية وهمية تفرض المرور الأول. تعبّر do while عن "جرّب، ثم قرّر هل تجرّب مجددًا" مباشرة.
قراءة المدخلات حتى قيمة حارسة
قراءة الأسطر حتى كلمة توقف، أو حتى نهاية المدخلات، هي حلقة while النموذجية. تعيد Console.ReadLine() القيمة null حين لا تبقى مدخلات، فاختبر الحالتين:
المخرجات:
skipping "abc": not a number
3 amounts, total 49.50
تُسند (line = Console.ReadLine()) != null السطر التالي وتختبره في تعبير واحد؛ والأقواس حول الإسناد إلزامية لأن != ترتبط بقوة أكبر من =. تتوقف الحلقة عند done، فلا يُقرأ 99 الذي بعدها أبدًا. ترفض decimal.TryParse النص abc دون رمي استثناء، وتتخطى continue إلى السطر التالي. ودون فحص null فإن بلوغ نهاية المدخلات سيمرّر null إلى TryParse إلى الأبد، لأن ReadLine تظل تعيد null.
تناسب do while نمط السؤال والتحقق، حيث يجب أن يظهر السؤال مرة واحدة على الأقل:
المخرجات:
Enter your age:
"-4" is not a valid age
Enter your age:
"fifteen" is not a valid age
Enter your age:
Age accepted: 15
السؤال داخل الحلقة، فيتكرر بعد كل إجابة مرفوضة، وage مصرّح بها قبل do كي تستخدمها الشيفرة بعد الحلقة. مع مستخدم أمام لوحة المفاتيح تظهر كل إجابة على الكونسول بعد سؤالها؛ ومع المدخلات المعاد توجيهها، كما هنا، لا يظهر إلا ما يطبعه البرنامج نفسه.
while (true) مع break
أحيانًا تكون نقطة الخروج الطبيعية في منتصف الجسم، بعد بعض العمل وقبل البقية. اكتب الحلقة بالشكل while (true) وغادرها بـ break:
المخرجات:
processing: resize photo
processing: send email
stop signal received
1 job(s) left in the queue
تأخذ Dequeue المهمة التالية من مقدمة الطابور، وتغادر الحلقة بمجرد أن ترى علامة التوقف، فتبقى المهمة الأخيرة في الطابور. ليست while (true) علامة على شيفرة سيئة حين يكون الخروج واضحًا وقريبًا من أعلى الجسم. وتصبح كذلك حين تتناثر عدة break في جسم طويل؛ حينها يكون شرط bool مسمّى أو دالة مع return أسهل تتبّعًا. تغطي صفحة break وcontinue مغادرة الحلقات المتداخلة.
حلقات لا تنتهي أبدًا
للحلقة اللانهائية غير المقصودة أحد ثلاثة أسباب.
الجسم لا يغيّر الشرط أبدًا. لا يُزاد العدّاد، أو يُزاد متغيّر خاطئ:
int i = 0;
while (i < 5)
{
Console.WriteLine(i); // i++ forgotten: prints 0 forever
}
فاصلة منقوطة بعد الشرط. الفاصلة المنقوطة هي جسم الحلقة كله، وتُنفَّذ الكتلة التي تحتها بعد الحلقة (التي لا تنتهي أبدًا):
while (retries < 3); // warning CS0642: Possible mistaken empty statement
{
retries++;
}
شرط يتخطى هدفه. اختبار != حين يتحرك المتغيّر بخطوات قد يقفز فوق قيمة التوقف. تسير while (x != 10) x += 3; بالقيم 0 و3 و6 و9 و12 وتتجاوز 10 مباشرة (ولا تقع على 10 إلا بالصدفة، بعد أن يتجاوز int سعته ويلتفّ بعد مليارات الخطوات). اختبر بـ < أو > بدل != كلما لم تكن الخطوة 1. وينطبق الأمر نفسه على قيم double، التي نادرًا ما تصيب هدفًا دقيقًا: while (x != 1.0) x += 0.1; لا تنتهي أبدًا.
الاختيار بين while وdo while وfor
| الحالة | الحلقة |
|---|---|
| عدد تكرارات معروف، أو فهرس | for |
| كل عنصر في مجموعة | foreach |
| التكرار ما دام شرط متحققًا، وربما صفر مرات | while |
| يجب تنفيذ الجسم مرة قبل أن يصبح للشرط معنى | do while |
| اختبار الخروج في منتصف الجسم | while (true) مع break |
يمكن إعادة كتابة أي حلقة for كحلقة while والعكس؛ والاختيار يتعلق بأيهما تضع منطق الحلقة حيث يتوقعه القارئ. حين يوجد العدّاد والاختبار والخطوة كلها تبقيها for في سطر واحد. وحين تقود الحلقة حالة تتغيّر داخل الجسم تقول while ذلك.
الأسئلة الشائعة
ما الفرق بين while وdo while في C#؟
تفحص حلقة while شرطها قبل كل تكرار، فيمكن أن يُنفَّذ جسمها صفر مرات. أما حلقة do { } while (condition); فتفحص بعد كل تكرار، فيُنفَّذ جسمها مرة واحدة على الأقل دائمًا. استخدم do while حين ينتج المرور الأول القيمة التي يختبرها الشرط، مثل قراءة المدخلات ثم التحقق منها.
ما صياغة حلقة do while في C#؟
do { body } while (condition);. لاحظ الفاصلة المنقوطة بعد القوس الختامي: إنها إلزامية، وحذفها خطأ ترجمة. يمكن للشرط أن يستخدم متغيّرات أُسند إليها في الجسم، لكن يجب التصريح بها قبل do، لأن أقواس الجسم نطاق منفصل.
كيف أكتب while (true) في C#؟
تدور while (true) { ... } إلى الأبد حتى يغادرها شيء من داخلها بـ break أو return أو استثناء. وهي الشكل الطبيعي حين يكون مكان اختبار الخروج في منتصف الجسم، مثل قراءة سطر والتوقف حين يكون فارغًا.
كيف أقرأ المدخلات حتى يكتب المستخدم كلمة أو تنتهي المدخلات في C#؟
دُر على Console.ReadLine()، التي تعيد null عند نهاية المدخلات: string line; while ((line = Console.ReadLine()) != null && line != "done") { ... }. يقرأ الإسناد داخل الشرط السطر التالي ويختبره في خطوة واحدة.
لماذا لا تنتهي حلقة while عندي في C#؟
عادة لأن الجسم لا يغيّر أبدًا ما يختبره الشرط (i++ منسية)، أو لوجود فاصلة منقوطة بعد الشرط مباشرة: while (count < 10); حلقة بجسم فارغ تدور إلى الأبد. يحذّر المترجم من الحالة الثانية بـ CS0642، Possible mistaken empty statement.