
base.Dispose. בלי הקריאה לבסיס המשאבים של המחלקה הבסיס לא ישוחררו.GC.SuppressFinalize כדי שהגארבג' קולקטור לא יפעיל את הדיסטרקטור פעם נוספת.disposing. בדיסטרקטור קוראים לאותה פונקציה עם false.disposing הוא true מכבים גם את המשאבים המנוהלים וגם את הלא מנוהלים. כש-false, רק את הלא מנוהלים, כי הדיסטרקטור לא יכול לגעת באובייקטים מנוהלים שאולי כבר נאספו.הטקסט המלא של הדקות הראשונות בהרצאה «Managing Resources - חלק 2» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
ובואו ניקח שלוש מחלקות שונות. המחלקה הראשונה שאנחנו הולכים להתעסק איתה זה מחלקה שיש בה ריסורס שנחשב מנג'ד. קודם כל יש הבדל בין ריסורס שנחשב מנג'ד ריסורס לבין ריסורס שנחשב אין מנג'ד.
מנג'ד מדבר על זה שהוא מנוהל על ידי הגרביץ' קולקטור. מנג'ד ממורי לדוגמה, זה זיכרון שמנוהל על ידי הגארבג' קולקטור, בגלל זה הזיכרון נקרא Managed Heap.
Unmanaged זה אזור זיכרון שלא מנוהל על ידי הגארבג' קולקטור, וזה בדרך כלל מתייחס לזיכרון שאובייקטים שלא שייכים ל.NET יוצרים. לדוגמה, מישהו כתב איזשהו DLL בשפת C שיוצר שם איזה משהו בזיכרון.
שום גארבג' קולקטור לא מכיר שום דבר בנוגע לזיכרון הזה. זה יהיה Unmanaged Memory, שמתבצע או שנכתב על ידי unmanaged code. אז כאן יש כמה הבדלים בין אם אנחנו מתעסקים עם resource שהוא managed לבין אם אנחנו מתעסקים ב-resource שהוא unmanaged.
אז בואו נפתח מחלקה ראשונה שמתעסקת אך ורק עם resource שהוא managed. נקרא לה managed resource. המחלקה הזאת היא בעצם מאוד דומה לlogger שמקודם ראינו, מפני שמה שיש לנו בתוך המחלקה הזאת זה resource רק .NETי, אז בואו נפתח פה private stream writer שמצביע על איזשהו קובץ כאן
אנחנו רואים שיש לנו מחלקה שיש לה data member שמכיל שהוא כמובן resource אבל הוא managed resource בלבד במקרה הזה אמרנו בואו נתחיל עם איזושהי פונקציה do work שעושה את העבודה אוקיי מה אנחנו עושים בתוך הפונקציה אז קודם כל אנחנו בתוך הפונקציה רוצים לבצע את העבודה
writer.rightline פה אנחנו עובדים. מעבר לזה אנחנו צריכים לטפל בכל נושא הסגירות. מה אמרנו שאנחנו עושים? אנחנו חייבים לרשת את iDisposable לממש בפונקציית dispose אנחנו רוצים לשחרר את המשאב writer.dispose למה אני אומר שאנחנו צריכים לעשות קצת יותר מזה?
מפני שמה שאנחנו צריכים לעשות זה כזה דבר קודם קודם כל קריאות מרובות לדיספוז לא אמורות לגרום לקריסה. אז בשביל למנוע את כל הסיפור של הקריסה מה שנעשה זה כזה דבר אחרי ששחררנו נלך ל-writer ונחניף לתוכו null בתחילה dispose נבדוק האם writer שווה ל-null
אנחנו לא רוצים לבצע קריסה כי אולי קריאה לדיספוז או סגירה שיש לנו כאן אומרת שאסור לנו לעשות את זה כמה פעמים אני לא יודע זה לא האובייקט שלי אז אם זה המצב כל מה שאנחנו צריכים לעשות זה להגיד רגע רגע מישהו כבר שחרר אותך אז אני לא רוצה לעשות שום דבר אני יוצא החוצה.
לא שחררו אותך אין בעיה אני משחרר ומכניס נאל בכדי שאם יקראו לי עוד פעם אני לא אקרוס אני ממש אצא ולא אעשה שום דבר. דבר נוסף בתוך do work אנחנו צריכים לבדוק האם יש פה נאל.
אם יש פה נאל אנחנו לא יכולים לעבוד עם האובייקט אבל אנחנו צריכים לברוק exception שנקראת object.dispose.exception ו-exception מיוחדת שקיימת בדוטנט שאומרת רגע רגע מישהו כבר עשה dispose לאובייקט שלכם יש שם איזה resource פנימי שנקרא writer ונא לא לעבוד איתו אתם לא יכולים לעבוד איתו כי
כבר ביצעתם dispose אז אסור לכם וכאן אנחנו רואים pattern שקשור לזה שאנחנו עובדים אך ורק עם managed resource. דבר נוסף שכדאי שנוסיף זה שהפונקציה dispose תהיה וירטואלית.
זאת נקודה חשובה כי יכול להיות שמישהו יבנה אחר כך פונקציה נוספת, מחלקה אחרת שיורשת את managed resource וגם לה יש איזשהו אובייקט אחר שהיא רוצה לשחרר.
אז לכן במידה במידה וזה מה שקורה צריכים לקרוא לבייס נקודה דיספוז. כלומר אם אנחנו רושמים פה קלאס נקרא לזה Managed Resource Extended, היא יורשת את Managed Resource ולה יש Private Stream Writer Another Writer והיא גם רוצה לדרוס אותו אז היא לא צריכה לרשת את I-Disposable מפני שהיא
כבר קיבלה את I-Disposable מבחוץ. כל מה שהיא צריכה לעשות זה Override על Dispose ואז לקרוא ל-Base.Dispose ואז לבצע את העניינים של השחרור שלה.
AnotherWriter.Dispose, AnotherWriter.A-Null וכמובן עם AnotherWriter.A-Null לצאת החוצה וכמובן כל הפאטרן כמו שראינו מקודם אבל שימו לב שבגלל שהדיספוז המקורית הוגדרה כווירטואל אנחנו עכשיו כשירשנו יכולים לעשות אובר רייד ולרשת את או לדרוס את דיספוז לקרוא לבייס נקודה דיספוז זאת
נקודה מאוד מאוד חשובה וקריטית אחרת אנחנו לא נשחרר את הדברים של הבסיס שלנו ואז ממשיכים ומשחררים את הדברים שקשורים אלינו אוקיי זה נקודה מעניינת שימו לב שאם המחלקה שלכם מוגדרה כ-sealed זה אומר שאי אפשר לרשת אותה במצב הזה אל תגדירו שום פונקציה וירטואלית במחלקה שלכם כי אין לזה שום היגיון.
אז במצב הזה היא לא תהיה וירטואלית בסדר אז כל מה שעשינו כרגע זה managed resource זאת אומרת איזושהי מחלקה שיש לה אך ורק רכיב שהוא נטי בלבד שה-garbage collector יכול לשחרר אותו והוא לא קשור ל-c++ ולכן זאת השיטה שבה אנחנו משחררים.
אבל יש עוד מקרה. מה קורה אם המחלקה שאנחנו בונים בכלל מכילה איזשהו resource שלא קשור ל-garbage collector ושקשור לאיזשהו זיכרון שהוא unmanaged וכאן יכולה להיות סכנה אחרת.
הסכנה האחרת שיכולה להיות כאן זה שאם התוכנית שלנו תיסגר אז בגלל שהריפורס הזה הוא Unmanaged התוכנית שלנו לא מכירה שום דבר לגביו והוא יכול לחיות לנצח בזיכרון כל עוד המחשב פעיל.
במצב כזה אנחנו צריכים לעשות עוד איזושהי הגנה שאנחנו לא היינו עושים אותה אם היה לנו משאב דוטנטי וההגנה אומרת אם שכח מי שמשתמש במחלקה לקרוא לדיספורס בכל מקרה אנחנו רוצים לקרוא לשחרור של המשאב שהוא unmanaged.
בואו נראה איך עושים את זה במחלקה נפרדת. פה אנחנו הולכים ללכת ולהוסיף, הולכים להוסיף איזושהי מחלקה ונקרא לה unmanaged resource.
אוקיי, במחלקה הזאת הולך להיות לנו איזשהו resource שלא קשור ל.NET בלבד, אז יש לנו פה פרייבט ובואו ניקח פוינטר. פוינטר זה בעצם איזשהו אובייקט שמסוגל להצביע על כל זיכרון במחשב, גם זיכרון שלא קשור לדוטנט.
בדרך כלל משתמשים איתו ב-C++ או ב-C ונניח שעל ההתחלה הוא מצביע על איזשהו מקום בזיכרון כלשהו. יש לנו פה פונקציה do work.
פה אנחנו מבצעים את אותו הדבר כמו שעשינו מקודם. פה אנחנו עובדים עם ה-resource, בואו אפילו נציג פה את הדבר הזה במקום ההערה, אבל אנחנו צריכים לבצע בדיוק את אותו הדבר כמו מקודם.
אם הפוינטר שלנו שהוא בעצם unmanaged resource מכיל שום דבר נניח מכיל 0 ואומר שמישהו כבר שחרר אותו. אם הוא לא מכיל 0 אתה יכול לעבוד איתו בבקשה אנחנו עובדים עם ה-resource.
איפה הוא אמור להכיל 0? כאשר מבצעים dispose. אנחנו צריכים לרשת את iDisposable לממש פונקציית Dispose.
בפונקציית Dispose אנחנו מבצעים את מה שעשינו מקודם. הפונקציה תהיה virtual כמו מקודם, אלא אם כן המחלקה שלנו היא sealed כמובן.
אם מישהו כבר שחרר לנו אותו, מישהו כבר קרא מקודם ל-Dispose,