NET/משפטי בקרה

< NET
תכנות בסביבת NET








משפט if הוא משפט תנאי. הפקודה שבתוך המשפט תתבצע אם ורק אם התנאי מתקיים.

במקרה של פקודה אחת, התחביר הוא כדלהלן:

C#:

if (condition)
  statement

condition הוא ביטוי בוליאני, כלומר ביטוי שערכו true או false.

statement היא פקודה לביצוע.

לדוגמה:

C#:

if (x > 5)
  Console.WriteLine("x is larger than 5");

המשפט x is larger than 5 יודפס רק אם ערך המשתנה x גדול מ-5.

במקרה של יותר מפקודה אחת, נשתמש בסוגריים מסולסלים כדי לסמן בלוק פקודות:

C#:

if (condition) {

  statement1
  statement2
  statement3
  ...

}

לדוגמה

C#:

if (x > 5) {

  int y = x + 2;
  Console.WriteLine(y);

}

בנוסף לציון ההוראות שיבוצעו אם ערך הביטוי הבוליאני של המשפט יהיה true, ניתן לציין גם מה יבוצע אם ערכו יהיה false, וזאת באמצעות בלוק else:

C#:

if (condition)

  statement1
else

  statement2

במקרה זה, אם ערך condition הוא true, יבוצע statement1. אם ערכו false, יבוצע statement2. גם כאן, statement2 יכול להיות בלוק של הוראות תחומות בסוגריים מסולסלות.

בעת שימוש במשפטי תנאי מקוננים (כלומר, statement1 הוא בעצמו משפט if), מומלץ מאוד להשתמש בסוגריים מסולסלות גם עבור הוראה אחת, כדי למנוע בלבול בשיוך ה-else ל-if הנכון. נסתכל בדוגמה הבאה:

C#:

if (x < 5)

  if (y < 3)
    Console.WriteLine("x < 5 and y < 3");
else

  Console.WriteLine("x >= 5");

קל לטעות ולחשוב שמשפט ה-else שייך ל-if החיצוני, אך מכיוון שהוא בא מייד לאחר ה-if הפנימי, הוא שייך לו. שימוש בסוגריים יבהיר את השייכות:

C#:

if (x < 5) {

  if (y < 3)
    Console.WriteLine("x < 5 and y < 5");
}
else {
  Console.WriteLine("x >= 5");

}

אופרטור תנאי

עריכה

לעתים נרצה לקבל ערך מסויים כאשר ערך ביטוי בוליאני מסויים הוא true, וערך אחר אם ערכו false. למשל, קטע הקוד הבא:

C#:

int x;

if (y > 5) {
  x = 3;
}
else {
  x = 4;

}

במקרים כאלה, בהם אנו רוצים לבצע השמה למשתנה (x במקרה שלנו) בהתאם לתנאי מסויים, ניתן לכתוב את התנאי בצורה מקוצרת, כך:

C#:

x = y > 5 ? 3 : 4;

כלומר, אם מתקיים התנאי y > 5, החזר את הערך 3 (במקום 3 יכול לבוא כל ביטוי המחזיר int במקרה זה), אחרת, החזר 4 (או כל ביטוי שערכו מסוג int).

יש לשים לב ששתי אפשרויות ההחזרה הן מאותו סוג, או שלפחות ניתן לבצע cast מהשניה לראשונה.

משפט switch (ב־VB:‏ Select Case) מאפשר לבדוק מספר ערכים אפשריים עבור ביטוי, ולבצע הוראה אחרת בכל מקרה (או לקבוע שאותה הוראה תבוצע עבור מספר ערכים מתוך האפשרויות). המשפט יכול גם להגדיר מה לבצע במקרה שערך הביטוי אינו שווה לאף אחת מהאפשרויות. תחביר המשפט הוא כדלהלן:

C#:

switch (expression) {

case val1:
  statement1
  break;
case val2:
  statement2
  break;
case val3:
  statement2
  break;
...
case val7:
case val8:
  statement7
  break;
default:
  default_statement
  break;

}

expression - ביטוי בעל ערך מספרי (מספר שלם או נקודה צפה מכל סוג) או מחרוזת.

statement1-7 - הוראות שיבוצעו במקרה שערך expression הוא val1-8.

default_statement - הוראה שתבוצע אם ערך הביטוי אינו אחת מהאפשרויות שהוזכרו.

שים לב שיש לציין את המילה השמורה break בסוף כל אפשרות, כדי למנוע אפשרות של מעבר הביצוע לאפשרות הבאה. השמטת המילה מהווה שגיאת תחביר ותכשיל את תהליך ההידור. האפשרות היחידה בה ניתן להשמיט אותה היא במקרה כמו val7 ו-val8. במקרה זה, statement7 תבוצע אם ערך הביטוי הוא val7 או val8. בצורת כתיב זו, אין לציין הוראה כלשהי בין case val7: ל-case val8:.

הערכים הנבדקים צריכים להיות קבועים ומפורשים. לא ניתן לציין ביטויים או משתנים בערכי val השונים.

דוגמה:

C#:

Console.WriteLine("Type a number:");

String str = Console.ReadLine();
switch (str) {
case "1":
  Console.WriteLine("You typed 1");
  break;
case "2":
  Console.WriteLine("You typed 2");
  break;
default:
  Console.WriteLine("You typed something else");
  break;

}

while מגדיר לולאה המתבצעת כל עוד מתקיים תנאי בוליאני. בתוך הלולאה יש אפס או יותר פקודות, המתבצעות בכל איטרציה של הלולאה. תחביר:

C#:

while (condition)
  statement

condition ביטוי בוליאני שערכו true או false

statement פקודה לביצוע. פקודה זו תתבצע כל עוד ערך condition הוא true.

סדר הביצוע של הלולאה הוא כדלהלן:

  1. הערך את הביטוי condition
  2. אם ערך condition הוא true, בצע את statement וחזור ל-1. אחרת, המשך לפקודה שאחרי משפט ה-while.

לדוגמה

C#:

while (x < 5)
  x++;

statement יכול להיות גם ריק. במקרה זה ביצוע התוכנית למעשה יעצר עד שהתנאי condition יתקיים. למעשה, התנאי ייבדק שוב ושוב, עד שערכו יהיה true. התחביר במקרה זה יהיה

C#:

while (condition);

במידה ויש יותר מפקודה אחת לביצוע, נכליל את הפקודות בסוגריים מסולסלות:

C#:

while (condition) {

  statement1
  statement2
  statement3
  ...

}

do ... while

עריכה

לולאת do-while מבוצעת לפחות פעם אחת, לפני שהתנאי נבדק. לולאה זו טובה במקרים בהם רוצים לבצע פקודה מסויימת לפחות פעם אחת, בלי קשר להתקיימות התנאי. התחביר שלה הוא כדלהלן:

C#:

do {

  statement1
  statement2
  statement3
  ...

} while (condition);

VB.NET:

Do

  statement1
  statement2
  statement3
  ...

Loop While condition

הלולאה מבוצעת בסדר הבא:

  1. בצע את ההוראות בלולאה
  2. בדוק את ערך הביטוי הבוליאני condition. אם ערכו true, חזור ל-1. אחרת, צא והמשך לאחר הלולאה.

בשפת Visual Basic יש צורה נוספת ללולאה זו. בצורה זו, הלולאה מבוצעת כל עוד התנאי condition אינו מתקיים. מבחינה לוגית, הדבר שקול לביצוע הלולאה כל עוד שלילת התנאי היא true. הצורה נכתבת כך:

VB.NET:

Do

  statement1
  statement2
  statement3
  ...

Loop Unless condition

והיא שקולה לצורה

VB.NET:

Do

  statement1
  statement2
  statement3
  ...

Loop While Not condition

אם ערך condition הוא false, שלילתו היא true, ולכן הלולאה ממשיכה להתבצע.

בצורת השימוש הבסיסית, לולאת for מיועדת לביצוע הוראה או קבוצת הוראות מספר קבוע מראש של פעמים. התחביר שלה הוא כדלהלן.

C#:

for (init; condition; update)
  statement

init - איתחול הלולאה.

condition - ביטוי בוליאני. הלולאה תתבצע אם ורק אם ערך ביטוי זה true

update - הוראה לעדכון. חייב להיות ביטוי השמה. ניתן להשתמש באופרטור אונארי, כמו ++.

statement - הוראה לביצוע

כמו בלולאות האחרות, גם כאן, כאשר יש יותר מהוראה אחת לביצוע בכל מחזור של הלולאה, הן יקובצו בבלוק:

C#:

for (init; condition; update) {

  statement1
  statement2
  statement3
  ...

}

הלולאה תבוצע בסדר הבא:

  1. בצע את init
  2. אם ערך condition הוא true, בצע את statement. אחרת, המשך לאחר הלולאה.
  3. בצע את update
  4. חזור לצעד 2.

לדוגמה:

C#:

for (int i = 0; i < 5; i++) {

  Console.WriteLine("i = " + i);

}

בדוגמה זו, חלק ה-init מאתחל משתנה חדש מסוג int עם הערך 0. משתנה זה יהיה ידוע רק בתוך הבלוק של משפט ה-if. בתחילה הביטוי i < 5 הוא true, ולכן מודפסת המחרוזת

i = 0

לאחר מכן ערך i עולה באחד בעזרת האופרטור ++, וערך התנאי נבדק שוב. הוא יהיה true עד שערך i יהיה 5, אז יופסק ביצוע הלולאה והתוכנית תמשיך להוראה הראשונה שאחריה. הפלט המלא יהיה

i = 0
i = 1
i = 2
i = 3
i = 4

עם זאת, אין חובה להשתמש בחלקים השונים של המשפט דווקא עם מספרים. ניתן לבצע כל הוראת השמה בחלק ה-init, לבצע כל הוראת השמה בחלק ה-update, ולבדוק כל ביטוי בוליאני בחלק ה-condition בלי קשר לחלקים האחרים. בנוסף, בחלק ה-update ניתן לבצע מספר הוראות, מופרדות בפסיקים. כל החלקים הם אופציונליים, וניתן לוותר על כל אחד מהם ועל כולם גם יחד (אך אין לוותר על סימני הנקודה-פסיק). לדוגמה:

C#:

for (;;) {

// statement

}

לולאה זו תתבצע אינסוף פעמים.

דוגמה:

C#:

String[] strArr = {"one", "two", "three"};

int i = 0;
String str = strArr[1];
for (String s = strArr[i]; Object.ReferenceEquals(str, strArr); s = strArr[i]) {
  i++;

}

לולאת foreach (ב-VB: ‏For Each) מיועדת למעבר על כל האיברים הנמצאים במבנה נתונים המממש את הממשק IEnumerable. בכל איטרציה של הלולאה מקבלים גישה לאיבר נוסף במבנה הנתונים, וניתן לקרוא אותו, לבצע עליו פעולות, וכד'. לא ניתן להוסיף או למחוק איברים ממבנה הנתונים בתוך הלולאה, משום שהדבר יפגע בלולאה, ולא יאפשר לדעת מה האיבר הבא. תחביר הלולאה הוא כדלהלן:

C#:

foreach (typename t in collection) {

  statement

}

typename - שם המחלקה של האיברים במבנה הנתונים

collection - ביטוי המחזיר ערך מסוג מחלקה המממשת את IEnumerable. מומלץ לשים במקום זה משתנה ולא קריאה לשגרה או מאפיין, משום שהקריאה של הביטוי תבוצע בכל מחזור של הלולאה, ותבזבז זמן עיבוד על ביצוע אותה פעולה שוב ושוב.

statement - הוראה לביצוע

כאשר t הוא משתנה מסוג typename המוכר בתוך הלולאה, ומקבל בכל פעם את האיבר הבא במבנה הנתונים. המילה השמורה in היא חלק בלתי נפרד מתחביר הלולאה, ואין להשמיט אותה.

ניקח לדוגמה מבנה נתונים מסוג מערך. כזכור, כל מערך הוא אובייקט של המחלקה Array, המממשת את IEnumerable. נסתכל על קטע הקוד הבא:

C#:

String strArr[] = new String[] {"one", "two", "three"};

foreach (String s in strArr) {
  Console.WriteLine(s);

}

קוד זה יקבל בכל איטרציה את ערך המחרוזת הבאה במערך אל המשתנה s, וידפיס אותו.

יש לציין שלולאת foreach מהירה בהרבה מלולאת for, ולכן במקומות שבהם ניתן להשתמש בה, עדיף לעשות זאת, במיוחד כאשר מטפלים במבני נתונים המחזיקים מאות איברים.

למען האמת, לולאת foreach אינה מוסיפה תכונה חדשה לשפה. תפקידה הוא רק להקל על המתכנת, הן בכתיבת קוד והן בקריאתו. הלולאה למעשה מהווה קיצור דרך לכתיבת קוד מפורש, שיקרא לשגרות המוגדרות בממשק IEnumerable, ו־IEnumerator המוחזר מהשגרה GetEnumerator שלו. הדוגמה הקודמת שקולה למעשה לכתיבת הקוד הבא:

C#:

String strArr[] = new String[] {"one", "two", "three"};

IEnumerator myEnum = strArr.GetEnumerator();
while (myEnum.MoveNext()) {
  Console.WriteLine(myEnum.Current);

}

break ו-continue

עריכה

המילים השמורות continue (ב־VB:‏ Continue For או Continue While) ו-break מאפשרות שליטה רבה יותר על לולאות for ו-while, על ידי שינוי סדר הפעולה של הלולאה.

המילה השמורה break מפסיקה לאלתר את פעולת הלולאה, ומעבירה את השליטה להוראה הראשונה שאחריה. לדוגמה:

C#:

for (int i = 1; i <= 100; i++) {

  if (i == 5) {
    break;
  }
  Console.WriteLine(i);

}

בדוגמה זו, הלולאה תופסק לאחר חמישה צעדים, כאשר ערך i יהיה 5.

המילה break משמשת כאמור גם במבנה הבקרה switch.

continue

עריכה

המילה השמורה continue מפסיקה את האיטרציה הנוכחית של הלולאה, וממשיכה לאיטרציה הבאה (תוך בדיקת ערך הביטוי הבוליאני בלולאות המתאימות). אם ניקח את הדוגמה הקודמת,

C#:

for (int i = 1; i <= 100; i++) {

  if (i == 5) {
    continue;
  }
  Console.WriteLine(i);

}

הפלט שלה יהיה

1
2
3
4
6
7
8
...
100

שים לב שדילגנו על מספר 5. כאשר i היה שווה 5, דילגנו לאיטרציה הבאה ולא ביצענו את ההדפסה.

ההוראה goto מעבירה את המשך ביצוע התוכנית לשורה המצויינת בעזרת תווית באותה שגרה, בלי קשר למיקום או המבנה התחבירי בו היא מופיעה. מסיבה זו רצוי מאוד לא להשתמש במילה זו לעולם. שימוש בפקודת goto שובר את הלוגיקה של התוכנית ומקשה על ניפוי שגיאות, ונחשב ככלל כהרגל תכנותי רע. לצורך שלמות המידע, נביא את תחביר הפקודה.

C#:

goto my_label;

...
my_label:

  statement

כאשר ביצוע התוכנית מגיע אל פקודת goto, הביצוע מפסיק וממשיך בפקודה שאחרי התווית my_label, המצויינת כאן על ידי statement.