Menu

אופרטורים ב-C#: חשבון, מודולו, לוגיקה, סיביות וקדימות

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

בדף הזה יש עורכים שאפשר להריץ. לערוך, להריץ ולראות את הפלט מיד.

אופרטור מקבל אופרנד אחד, שניים או שלושה ומפיק ערך: a + b, !done, x ?? fallback. האופרטורים של C# קרובים לאלה של C, Java ו-JavaScript, אבל כמה מהם מתנהגים בדרכים שמפתיעות מתחילים, ובראשם חילוק שלמים והסימן של %.

אופרטורים אריתמטיים

+, -, *, / ו-% עובדים על כל טיפוס מספרי. הטיפוס של התוצאה נקבע לפי האופרנדים: שני ערכי int מפיקים int, ו-int עם double מפיקים double.

פלט:

22
12
85
3
2
3.4
3.4
3
3.4

חילוק שלמים מקטם לכיוון אפס. 17 / 5 הוא 3 ו--17 / 5 הוא -3. זה גורם לבאג נפוץ מאוד: int percent = done / total * 100; הוא 0 בכל פעם ש-done < total, כי done / total כבר 0. הכפילו קודם (done * 100 / total) או חלקו כ-double.

חילוק של מספר שלם או decimal באפס זורק DivideByZeroException. חילוק של double באפס לא זורק; הוא מפיק אינסוף, או NaN עבור 0.0 / 0.0:

פלט:

True
True
False
DivideByZeroException

אופרטור המודולו ומספרים שליליים

% מחזיר את השארית של החילוק, והתוצאה שלו מקבלת את הסימן של האופרנד השמאלי. זה שונה מ-Python ומה-"mod" המתמטי, שתמיד אינם שליליים כשהמחלק חיובי:

פלט:

1
-1
1
2
even
62 min 5 s
Thu
1.5

השתמשו בפונקציית העזר Mod בכל פעם שהצד השמאלי יכול להיות שלילי והתוצאה היא אינדקס: days[(today + offset) % 7] היה זורק IndexOutOfRangeException עבור סכום שלילי. בבדיקת מספרים אי-זוגיים יש אותה מלכודת: n % 2 == 1 הוא false עבור מספרים אי-זוגיים שליליים; בדקו n % 2 != 0.

השמה, השמה מורכבת והגדלה

= מבצע השמה. הצורות המורכבות +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= משלבות פעולה עם השמה. ++ ו--- מוסיפים או מחסירים 1, ויש להם צורת תחילית וצורת סופית שנבדלות בערך שהן מחזירות:

פלט:

14
start, step
a=5 b=7 i=7
4

המקרה של byte מראה מוזרות: level = level + 10; לא מתקמפל, כי byte + int הוא int, אבל level += 10; כן מתקמפל, כי השמה מורכבת כוללת המרה מרומזת חזרה לטיפוס של המשתנה. ההמרה הזו מתגלגלת בגלישה (250 + 10 הופך ל-4).

אופרטורי השוואה ואופרטורים לוגיים

אופרטורי השוואה (==, !=, <, >, <=, >=) מחזירים bool. במחרוזות, == משווה את הטקסט, לא את ההפניות. האופרטורים הלוגיים הם ! (לא), && (וגם), || (או) ו-^ (או בלעדי).

פלט:

True
no active user
with ||:
  evaluated A
with |:
  evaluated A
  evaluated B
True

&& ו-|| מקצרים: האופרנד הימני רץ רק כשהוא יכול לשנות את התוצאה. זה מה שהופך את user != null && user.IsActive לבטוח. & ו-| בודדים על ערכים בוליאניים תמיד מחשבים את שני הצדדים, וזה רק לעיתים רחוקות מה שרוצים בתנאי.

אופרטורי סיביות והזזה

על טיפוסים שלמים, &, |, ^ ו-~ פועלים על סיביות בודדות, ו-<< ו->> מזיזים אותן. משתמשים בהם לדגלים, למסכות, לגיבוב ולפרוטוקולים ברמה נמוכה:

פלט:

3
True
False
101
1024
125
5
-1

לקבוצות דגלים עם שמות, enum עם התכונה [Flags] ברור יותר מקבועים שלמים, ו-HasFlag קריא יותר ממסכה. C# 11 הוסיפה את >>>, הזזה ימינה ללא סימן שממלאת באפסים גם במספרים שליליים.

אופרטורי null

יש שלושה אופרטורים לעבודה עם ערכים שעשויים להיות null:

פלט:

Guest

0
5

a ?? b מחזיר את a אלא אם הוא null, ואז את b. a?.Member מחזיר null במקום לזרוק חריגה כש-a הוא null. C# 8 הוסיפה את a ??= b, שמציב את b ב-a רק כש-a הוא null. הם מוסברים לעומק בדף על טיפוסי nullable.

קדימות אופרטורים

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

קטגוריהאופרטורים
ראשייםx.y, x?.y, f(x), a[i], x++, x--, new, typeof, nameof
אונריים+x, -x, !x, ~x, ++x, --x, (T)x, await
כפליים*, /, %
חיבוריים+, -
הזזה<<, >>, >>>
יחס ובדיקת טיפוס<, >, <=, >=, is, as
שוויון==, !=
AND ברמת סיביות&
XOR ברמת סיביות^
OR ברמת סיביות|
AND מותנה&&
OR מותנה||
Null coalescing??
מותנהc ? a : b
השמה ולמבדה=, +=, -=, ??=, =>, ושאר הצורות המורכבות

שתי השלכות שכדאי להכיר: a + b * c מכפיל קודם, ו-x & mask == 0 משווה קודם (== נקשר חזק יותר מ-&), כך שמשמעותו x & (mask == 0) והוא לא מתקמפל עם מספרים שלמים. כתבו (x & mask) == 0. סוגריים לא עולים כלום והופכים את הכוונה לברורה.

העמסת אופרטורים

הטיפוסים שלכם יכולים להגדיר מה משמעות האופרטורים. כך decimal, DateTime ו-TimeSpan תומכים ב-+ וב-<:

פלט:

33.49
True

אופרטורים חייבים להיות public static, וחלקם מגיעים בזוגות מחייבים: הגדרה של < מחייבת את >, ו-== מחייב את !=. כש-== מוגדר, הקומפיילר גם מזהיר עד שתדרסו את Equals ואת GetHashCode בהתאם. העמיסו אופרטורים רק כשהמשמעות ברורה, כמו במספרים, וקטורים וכסף.

שאלות נפוצות

מה עושה % ב-C#?

% הוא אופרטור השארית: 17 % 5 הוא 2. לתוצאה יש את הסימן של האופרנד השמאלי, כך ש--7 % 3 הוא -1, ולא 2 כמו ב-Python. כדי לקבל תוצאה שתמיד אינה שלילית, כמו שצריך כשמגלגלים אינדקס, כתבו ((a % n) + n) % n. הוא עובד גם על double ועל decimal: 7.5 % 2 הוא 1.5.

למה 7 / 2 שווה 3 ב-C#?

כששני האופרנדים הם מספרים שלמים, / מבצע חילוק שלמים ומשליך את החלק השברי, בקיטום לכיוון אפס. הפכו אופרנד אחד לערך נקודה צפה או decimal כדי לקבל תוצאה שברית: 7 / 2.0 הוא 3.5, (double)a / b ממיר לפני החילוק, ו-7m / 2 הוא 3.5 בתור decimal.

מה ההבדל בין && ל-& ב-C#?

&& הוא AND מותנה: אם הצד השמאלי הוא false, הצד הימני לא מחושב. & על ערכים בוליאניים תמיד מחשב את שני הצדדים, ועל מספרים שלמים הוא AND ברמת הסיביות. השתמשו ב-&& וב-|| לתנאים, במיוחד בשומרים כמו user != null && user.IsActive, שעם & היו זורקים NullReferenceException.

מה ההבדל בין i++ ל-++i ב-C#?

שניהם מוסיפים 1 ל-i. הביטוי i++ מחזיר את הערך הישן, ו-++i את הערך החדש. בשורה נפרדת (i++;) אין הבדל. זה משנה רק כשמשתמשים בתוצאה, כמו ב-int a = i++;, ולכן הרבה מדריכי סגנון שומרים הגדלות בשורה משלהן.

מהו סדר הקדימות של האופרטורים ב-C#?

מהגבוה לנמוך: ראשיים (x.y, f(x), a[i], x++), אונריים (!, -, ++x, המרות), כפליים (* / %), חיבוריים (+ -), הזזות, יחס (< > <= >= is as), שוויון (== !=), &, ^, |, &&, ||, ??, האופרטור המותנה ?:, ולבסוף השמה. כשיש ספק, הוסיפו סוגריים.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל