Menu

C# static: מחלקות, מתודות, שדות ובנאים סטטיים

מה המשמעות של static ב-C#: איברים ששייכים לטיפוס ולא לאובייקט, מצב משותף בין מופעים, מתודות סטטיות ומחלקות סטטיות, בנאים סטטיים, const מול static readonly, using static, והשגיאה CS0120.

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

static מסמן איבר ששייך לטיפוס, לא לאובייקט. שדה מופע קיים פעם אחת לכל אובייקט; שדה סטטי קיים פעם אחת, וזהו. מתודת מופע רצה על אובייקט (order.Ship()); מתודה סטטית רצה על הטיפוס (Math.Round(x)) ולא צריכה אובייקט בכלל.

שדות סטטיים: עותק אחד, משותף

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

פלט:

Ana #1, Ben #2, Chen #3
Orders created: 3

ניגשים לאיברים סטטיים דרך שם הטיפוס: Order.Created, לא a.Created. C# לא מאפשרת להגיע לאיבר סטטי דרך מופע (שגיאה CS0176), וכך ברור במקום הקריאה שהערך משותף.

מתודות סטטיות

למתודה סטטית אין this. היא עובדת רק עם הפרמטרים שלה ועם איברים סטטיים אחרים. זה הופך אותה לצורה הטבעית לפונקציות עזר שמחשבות משהו מהקלטים שלהן:

פלט:

61.38 EUR
7

גם Main עצמה סטטית: סביבת הריצה קוראת לה לפני שקיים אובייקט כלשהו.

השגיאה CS0120: קוד סטטי שמשתמש באיברי מופע

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

class Program
{
    int visits;
    void Greet() { Console.WriteLine("Hello"); }

    static void Main()
    {
        Greet();    // error CS0120: An object reference is required for the non-static field, method, or property 'Program.Greet()'
        visits++;   // error CS0120: An object reference is required for the non-static field, method, or property 'Program.visits'
    }
}

למתודה סטטית אין אובייקט, ולכן אין לה visits להגדיל. יש שני תיקונים, והנכון תלוי במה שהאיבר מייצג:

  • האיבר באמת הוא נתון של אובייקט: צרו אובייקט והשתמשו בו. var app = new Program(); app.Greet();
  • האיבר לא צריך מצב של אובייקט: סמנו אותו static. static void Greet() { ... }

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

הכיוון ההפוך תמיד מותר: מתודות מופע יכולות לקרוא לאיברים סטטיים בחופשיות.

מחלקות סטטיות

מחלקה שמוצהרת static יכולה להכיל רק איברים סטטיים, ואי אפשר ליצור ממנה מופע אף פעם. היא קבוצה של פונקציות וקבועים עם שם.

פלט:

77
100
True

הקומפיילר אוכף את החוזה: איבר מופע בתוך מחלקה סטטית הוא שגיאה CS0708, ו-new עליה הוא שגיאה CS0712. Math, Console, File, Path ו-Enumerable הן כולן מחלקות סטטיות. גם מתודות הרחבה חייבות לשבת במחלקה סטטית.

בנאים סטטיים ו-static readonly

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

פלט:

Before first use
ShippingRates initialized
5.50
3
2026-01-01

readonly אומר שאפשר להציב ערך בשדה רק באתחול שלו או בבנאי הסטטי. אחרי זה אי אפשר להציב בו ערך חדש, אם כי האובייקט שהוא מצביע עליו עדיין יכול להיות ניתן לשינוי, ולכן המילון נחשף כ-IReadOnlyDictionary.

const מול static readonly

שניהם נותנים ערך עם שם שמשותף לכל התוכנית, והם נבדלים ברגע שבו הערך נקבע:

conststatic readonly
הערך נקבעבזמן קומפילציהבזמן ריצה, פעם אחת
טיפוסים מותריםמספרים, char, bool, string, enums, nullכל טיפוס
סטטי במרומזכן (אי אפשר לכתוב static const)מוצהר סטטי במפורש
מועתק ל-assemblies הקוראיםכןלא, נקרא מהשדה
שמיש ב-cases של switch ובארגומנטים של תכונותכןלא

שורת ההעתקה חשובה בספריות: אם assembly A מצהיר על public const int MaxItems = 50; ו-assembly B משתמש בו, B מכיל את הליטרל 50. שינוי של A ל-100 לא עושה כלום ל-B עד ש-B מקומפל מחדש. לערכים שעשויים להשתנות בין גרסאות, העדיפו static readonly.

using static

הנחיית using static (C# 6) מייבאת את האיברים הסטטיים של טיפוס, כך שאפשר לקרוא להם בלי שם הטיפוס:

פלט:

Area: 28.27
40

זה נקרא טוב בקוד עתיר חישובים מתמטיים. במקומות אחרים השתמשו בזה במשורה: WriteLine או Parse חשופים מסתירים מאיזה טיפוס המתודה מגיעה.

מצב סטטי ותהליכונים

שדה סטטי משותף לכל התהליכונים בתהליך. הגדלה שלו מכמה תהליכונים בבת אחת מאבדת עדכונים, כי created++ הוא קריאה, חיבור וכתיבה, ושני תהליכונים יכולים לשזור אותם זה בזה. השתמשו ב-Interlocked.Increment(ref created) למונים, או ב-lock לכל דבר גדול יותר. אפליקציות web הן המקום הרגיל שבו זה נושך: כל בקשה רצה על תהליכון כלשהו, כך ששדה סטטי שמחזיק את "המשתמש הנוכחי" משותף לכל המשתמשים.

עוד דקות אחת: במחלקה גנרית, כל טיפוס שנבנה מקבל שדות סטטיים משלו. Cache<int>.Count ו-Cache<string>.Count הם שני שדות שונים.

מתי להשתמש ב-static

שימושים טובים:

  • פונקציות עזר טהורות שמחשבות תוצאה מהארגומנטים שלהן: עיצוב, המרות, אימות.
  • קבועים ונתוני חיפוש לקריאה בלבד שמשותפים לתוכנית.
  • מתודות factory, כמו TimeSpan.FromMinutes(5) או Temperature.FromCelsius(21) משלכם.
  • מתודות הרחבה.

שימושים גרועים:

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

שאלות נפוצות

מה המשמעות של static ב-C#?

איבר static שייך לטיפוס עצמו ולא לאובייקט כלשהו. יש עותק אחד של שדה סטטי, לא משנה כמה אובייקטים קיימים, ולמתודה סטטית קוראים על שם הטיפוס (Math.Max(3, 7)) בלי ליצור מופע. למתודה סטטית אין this, ולכן היא לא יכולה להשתמש ישירות בשדות מופע.

מה זו מחלקה סטטית ב-C#?

מחלקה שמוצהרת static יכולה להכיל רק איברים סטטיים, ואי אפשר ליצור ממנה מופע אף פעם (new עליה היא שגיאה CS0712). היא מקבצת פונקציות קשורות שלא צריכות מצב של אובייקט, כמו Math, Console או File. מתודות הרחבה חייבות להיות מוצהרות במחלקה סטטית.

איך מתקנים את השגיאה "An object reference is required for the non-static field, method, or property"?

זו שגיאה CS0120: מתודה סטטית, לעיתים קרובות Main, משתמשת באיבר מופע. או שיוצרים אובייקט וקוראים לאיבר עליו (var app = new Program(); app.Run();), או שמסמנים את האיבר כ-static אם הוא לא צריך נתונים של אובייקט מסוים.

מה ההבדל בין const ל-static readonly ב-C#?

const הוא קבוע בזמן קומפילציה (מספרים, מחרוזות, bool, enums) שהערך שלו מועתק לכל assembly שמשתמש בו. שדה static readonly מקבל ערך פעם אחת בזמן ריצה, באתחול שלו או בבנאי הסטטי, ויכול להחזיק כל טיפוס, כמו DateTime או רשימה. השתמשו ב-const לערכים שלעולם לא ישתנו, וב-static readonly לכל השאר.

מתי להשתמש ב-static ב-C#?

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

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

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

להתחיל