במאמר, קידוד מופעים חדשים של אובייקטים, כתבתי על הדרכים השונות בהן חדש ניתן ליצור מקרים של אובייקטים. הבעיה ההפוכה, השלכת חפץ, היא דבר שלא תצטרך לדאוג אליו ב- VB.NET לעתים קרובות מאוד. .NET כוללת טכנולוגיה הנקראת אוסף זבל (GC) שלרוב דואג לכל מה שמאחורי הקלעים בשקט וביעילות. אבל מדי פעם, בדרך כלל בעת שימוש בזרמי קבצים, אובייקטים של sql או גרפיקה (GDI +) (כלומר, משאבים לא מנוהלים), יתכן שתצטרך להשתלט על השלכת חפצים בקוד שלך.
ראשית, קצת רקע
בדיוק כמו קוןבניה (ה חדש מילת מפתח) יוצר חדש חפץ, א דהסטרוקטור הוא שיטה הנקראת כאשר חפץ מושמד. אבל יש מלכוד. האנשים שיצרו .NET הבינו שזו נוסחה לבאגים אם שתי פיסות קוד שונות יכולות למעשה להרוס אובייקט. אז .NET GC הוא למעשה בשליטה וזה בדרך כלל הקוד היחיד שיכול להרוס את מופע האובייקט. ה- GC משמיד אובייקט כשהוא מחליט ולא לפני כן. בדרך כלל, לאחר שהאובייקט משאיר את היקפו, זה כן שוחרר לפי זמן ריצה של שפה נפוצה (CLR). ה- GC הורס אובייקטים כאשר ה- CLR זקוק ליותר זיכרון פנוי. אז בשורה התחתונה אתה לא יכול לחזות מתי GC באמת יהרוס את האובייקט.
(טוב... זה נכון כמעט כל הזמן. אתה יכול להתקשר
GC.Collect וכוח א מחזור איסוף אשפהאבל הרשויות אומרות באופן אוניברסלי שזה א רע רעיון ומיותר לחלוטין.)לדוגמה, אם הקוד שלך יצר צרכן אובייקט, נראה כי קוד זה יהרוס אותו שוב.
לקוח = כלום
אבל זה לא. (בדרך כלל נקרא הגדרת אובייקט לכלום, הפיכה למעשה, זה רק אומר שהמשתנה כבר לא קשור לאובייקט. זמן מה לאחר מכן, ה- GC יבחין כי האובייקט זמין להשמדה.
אגב, עבור חפצים מנוהלים, כל זה לא באמת נחוץ. למרות שאובייקט כמו כפתור יציע שיטת סילוק, זה לא הכרחי להשתמש בו ומעט אנשים עושים זאת. רכיבי Windows Forms, למשל, מתווספים לאובייקט מכיל בשם רכיבים. כשאתה סוגר טופס, שיטת הסילוק שלו נקראת אוטומטית. בדרך כלל אתה צריך לדאוג לכל אחד מהדברים כשמשתמשים באובייקטים לא מנוהלים, וגם אז רק כדי לאפשר אופטימיזציה לתוכנית שלך.
הדרך המומלצת לשחרר את כל המשאבים שעלולים להיות בידי אובייקט היא להתקשר אל השלך שיטה לאובייקט (אם יש זמין) ואז לבטל את האובייקט.
צרכן. השלך () לקוח = כלום
מכיוון ש- GC יהרוס אובייקט יתום, בין אם תגדיר את משתנה האובייקט או לא, זה לא באמת הכרחי.
דרך מומלצת נוספת לוודא שאובייקטים נהרסים כשאין צורך בהם יותר היא להכניס את הקוד שמשתמש באובייקט ל- a באמצעות חסום. חסימת שימוש מבטיחה לרשות משאבים כאלה או יותר לאחר סיום הקוד שלך איתם.
בסדרת GDI +, ה- באמצעות ניתן להשתמש בלוק לעתים קרובות למדי לניהול אובייקטים גרפיים מציקים. לדוגמה ...
שימוש ב- myBrush כ- LinearGradientBrush _. = חדש LinearGradientBush (_. אני. מלבן לקוח, _. צבע. צבע כחול. אדום, _. LinearGradientMode. אופקי) <... ...> סיום השימוש
myBrush נפטר באופן אוטומטי כשמבוצע סוף הבלוק.
גישת ה- GC לניהול זיכרון היא שינוי גדול מהאופן בו VB6 עשתה זאת. אובייקטים של COM (המשמשים את VB6) נהרסו כאשר מונה הפניות פנימי הגיע לאפס. אבל זה היה קל מדי לטעות כך שהדלפק הפנימי לא היה פעיל. (מכיוון שהזיכרון היה קשור ולא היה זמין לחפצים אחרים כשזה קרה, זה נקרא "דליפת זיכרון".) במקום זאת, GC בעצם בודק אם משהו מתייחס לאובייקט ומשמיד אותו כשאין יותר הפניות. לגישת ה- GC יש היסטוריה טובה בשפות כמו Java והיא אחת השיפורים הגדולים ב- .NET.
בעמוד הבא אנו בודקים את הממשק המזהה... הממשק שישמש כשאתה צריך למחוק אובייקטים לא מנוהלים בקוד שלך.
אם אתה מקודד אובייקט משלך המשתמש במשאבים לא מנוהלים, עליך להשתמש ב- ניתן להזהיר ממשק לאובייקט. מיקרוסופט מקלה על כך על ידי הוספת קטע קוד היוצר את התבנית המתאימה לך.
לחץ כאן כדי להציג את האיור
לחץ על כפתור הקודם בדפדפן כדי לחזור
הקוד שנוסף נראה כך (VB.NET 2008):
Class ResourceClass. מיישם ניתן להזהרה. 'לגלות שיחות מיותרות. נפטר כבית בוליאני = לא נכון. ניתן להזהיר. השלך מוגן להחלפת משנה (_. ByVal נפטר כמו בוליאני) אם לא אני. אם נפטר אז. 'חופש מדינה אחרת (חפצים מנוהלים). סוף אם. 'שחרר את המדינה שלך (חפצים לא מנוהלים). 'הגדר שדות גדולים לביטול. סוף אם. Me.disposed = נכון. סיום משנה #Region "תמיכת IDISPOSable" קוד זה שנוסף על ידי Visual Basic ל-. ליישם כראוי את התבנית הפנויה. פריקת משנה ציבורית () מיישמת ניתן להזהרה. השלך. 'אל תשנה את הקוד הזה. 'הכנס קוד ניקוי. לזרוק (ByVal להיפטר כמו בוליאני) לעיל. השלך (נכון) GC. SuppressFinalize (Me) Sub Sub. סיום המשנה לעקיפות מוגנות () 'אל תשנה קוד זה. 'הכנס קוד ניקוי. לזרוק (ByVal להיפטר כמו בוליאני) לעיל. השלך (לא נכון) את MyBase. סיים () סיום משנה. # אזורnd. סיום כיתה
השלך הוא כמעט דפוס עיצוב "מאולץ" של מפתחים ב- .NET. יש באמת רק דרך אחת נכונה לעשות את זה וזהו. אתה יכול לחשוב שהקוד הזה עושה משהו קסם. זה לא.
ראשית שימו לב שהדגל הפנימי מסולק פשוט מקצר את כל העניין כדי שתוכל להתקשר להיפטר (להיפטר) לעתים קרובות ככל שתרצה.
הקוד ...
GC.SuppressFinalize (אותי)
... מייעל את הקוד שלך על ידי אומר ל- GC שהאובייקט כבר הושלך (פעולה 'יקרה' מבחינת מחזורי ביצוע). Finalize מוגן מכיוון ש- GC קורא לו אוטומטית כאשר אובייקט נהרס. אסור לך להתקשר לגמר. הבוליאני מסלק מורה לקוד אם הקוד שלך יזם את סילוק האובייקט (נכון) או האם ה- GC עשה זאת (כחלק מה- סיים תת. שים לב שהקוד היחיד המשתמש בבוליאני מסלק הוא:
אם נפטר אז. 'חופש מדינה אחרת (חפצים מנוהלים). סוף אם
כשאתה מסלק חפץ, יש לסלק את כל המשאבים שלו. כאשר ה- CLR אוסף זבל מסלק אובייקט רק יש לסלק את המשאבים הלא מנוהלים מכיוון שאספן האשפה דואג אוטומטית למשאבים המנוהלים.
הרעיון שמאחורי קטע קוד זה הוא להוסיף קוד כדי לטפל באובייקטים מנוהלים ולא מנוהלים במיקומים המצוינים.
כשאתה שואב כיתה מא מחלקת בסיס שמיישם את IDisposable, אינך צריך לעקוף אף אחת משיטות הבסיס אלא אם כן אתה משתמש במשאבים אחרים שצריך גם להיפטר מהם. אם זה קורה, המחלקה הנגזרת צריכה לעקוף את שיטת הסילוק (סילוק) של מחלקת הבסיס כדי להיפטר משאבי הכיתה הנגזרת. אך זכרו לקרוא לשיטת השלילה (סילוק) של מחלקת הבסיס.
מגן על עקיפות מוגנות משנה (סילוק ByVal כ בוליאני) אם לא. אם נפטר אז. 'הוסף את הקוד שלך למקורות מנוהלים בחינם. סוף אם. 'הוסף את הקוד שלך למקורות חופשיים שאינם מנוהלים. סוף אם. MyBase. להיפטר (להיפטר) סיום משנה
הנושא יכול להיות מעט מכריע. מטרת ההסבר כאן היא "לפזר" את מה שקורה בפועל מכיוון שרוב המידע שתוכלו למצוא אינו אומר לך!