PracticU

Managing Resources - חלק 2

בלי כתוביותעם כתוביות
PracticU › קורס תכנות מתקדם - #Advanced .NET C › Managing Resources - חלק 2
מילון מושגים:
תבנית - מבנה בסיסי מוכן שממנו יוצרים פריטים דומים, כמו תבנית עמוד או תבנית מסמך.
.NET - פלטפורמת פיתוח של מיקרוסופט להרצת יישומים בשפות כמו C#, הכוללת ספריות וסביבת ריצה משותפות.
DLL - קובץ ספרייה ב-Windows המכיל קוד ופונקציות שתוכנות שונות יכולות לטעון ולהשתמש בהן במשותף.
ירושה - מנגנון בתכנות מונחה עצמים שבו מחלקה יורשת תכונות ופעולות ממחלקת אב, ויכולה להרחיב אותן.
מתודה - פונקציה המוגדרת בתוך מחלקה ומתארת פעולה שאובייקטים מאותה מחלקה יכולים לבצע.
ספרייה - אוסף קוד מוכן, כמו פונקציות ומחלקות, שמפתחים משתמשים בו בתוכניותיהם במקום לכתוב הכול מחדש.
טופס - אזור בממשק שבו המשתמש מזין נתונים בשדות ושולח אותם, למשל טופס הרשמה או התחברות.
חריגה - מצב שגיאה שמתרחש בזמן ריצת התוכנית ומפסיק את המהלך הרגיל, אלא אם הקוד תופס ומטפל בו.

Managing Resources - חלק 2
השיעור ממשיך את נושא ניהול המשאבים ומציג את תבנית ה-Dispose: הדרך הנכונה לשחרר משאבים במחלקה, כשהם מנוהלים על ידי .NET, כשהם לא מנוהלים, וכששני הסוגים נמצאים יחד.
משאב מנוהל ומשאב לא מנוהל
1. מנוהל: משאב שהוא טיפוס .NET, כמו StreamWriter. ה-Garbage Collector יודע לשחרר את הזיכרון שלו, אבל הסגירה של הקובץ עדיין דורשת קריאה ל-Dispose.
2. לא מנוהל: זיכרון או קוד שנכתב בשפה אחרת, למשל DLL ב-C שיוצר אזור זיכרון. ה-Garbage Collector לא מכיר אותו בכלל, ולכן חייבים לשחרר אותו בעצמנו.
משאב מנוהל בלבד
3. המחלקה: מחלקה עם שדה StreamWriter. היא מממשת IDisposable, ומתודת Dispose בודקת אם הכתיבה כבר שוחררה. אם לא, היא סוגרת את ה-StreamWriter ומכניסה null לשדה.
4. קריאה כפולה: קריאות חוזרות ל-Dispose לא אמורות לגרום לקריסה, ולכן הבדיקה מונעת שחרור כפול.
5. שימוש אחרי Dispose: פונקציה שמנסה לעבוד עם האובייקט אחרי שנקרא לה Dispose זורקת ObjectDisposedException.
6. Virtual: Dispose מוגדרת כ-virtual, כדי שמחלקה שתרש אותה תוכל לדרוס את הפונקציה, לשחרר את המשאבים שלה, ולקרוא ל-base.Dispose. בלי הקריאה לבסיס המשאבים של המחלקה הבסיס לא ישוחררו.
7. Sealed: מחלקה שמוגדרת כ-sealed לא ניתנת לירושה, ולכן אין טעם להגדיר בה מתודה virtual.
משאב לא מנוהל
8. השדה: פוינטר לזיכרון לא מנוהל. בדרך כלל יש גם פונקציה מקבילה של הספרייה הלא מנוהלת שמשחררת את הזיכרון.
9. הרשת ביטחון: אם מתכנת השכח לקרוא ל-Dispose, המשאב הלא מנוהל יישאר בזיכרון עד שהתוכנית תיסגר. לכן מוסיפים דיסטרקטור שמשחרר אותו.
10. ביטול הדיסטרקטור: כשמישהו כבר קרא ל-Dispose, קוראים ל-GC.SuppressFinalize כדי שהגארבג' קולקטור לא יפעיל את הדיסטרקטור פעם נוספת.
משאב מנוהל ולא מנוהל יחד
11. תבנית מורכבת: מממשים Dispose ציבורי שקורא ל-Dispose מוגן עם הפרמטר disposing. בדיסטרקטור קוראים לאותה פונקציה עם false.
12. הפרמטר: כש-disposing הוא true מכבים גם את המשאבים המנוהלים וגם את הלא מנוהלים. כש-false, רק את הלא מנוהלים, כי הדיסטרקטור לא יכול לגעת באובייקטים מנוהלים שאולי כבר נאספו.
13. דוגמה ב-Windows Forms: בקובץ ה-Designer של טופס מופיעה אותה תבנית, כי הטופס מכיל גם רכיבים מנוהלים וגם משאבים לא מנוהלים.
שימוש במחלקה
14. using לעומת קריאה ידנית: מי שמשתמש במחלקה שמממשת IDisposable עובד בתוך בלוק using. כך Dispose נקרא גם בחריגה.
התבנית הזאת מונעת דליפות של משאבים, וכל מי שכותב מחלקה עם משאב חייב להכיר אותה.
השיעור הבא בקורס: תרגילים על Managing Resources

פרקי ההרצאה: Managing Resources - חלק 2

  1. 00:00

    ההבדל בין Managed ל-Unmanaged Resource

  2. 01:23

    מחלקת Managed Resource עם StreamWriter

  3. 03:10

    מניעת קריסה בקריאות מרובות ל-Dispose

  4. 04:47

    Dispose וירטואלי לצורך הורשה

  5. 07:45

    טיפול ב-Unmanaged Resource

  6. 09:02

    מחלקת Unmanaged Resource עם Pointer

תמלול ההרצאה: Managing Resources - חלק 2

הטקסט המלא של הדקות הראשונות בהרצאה «Managing Resources - חלק 2» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.

  1. 00:09

    ובואו ניקח שלוש מחלקות שונות. המחלקה הראשונה שאנחנו הולכים להתעסק איתה זה מחלקה שיש בה ריסורס שנחשב מנג'ד. קודם כל יש הבדל בין ריסורס שנחשב מנג'ד ריסורס לבין ריסורס שנחשב אין מנג'ד.

  2. 00:35

    מנג'ד מדבר על זה שהוא מנוהל על ידי הגרביץ' קולקטור. מנג'ד ממורי לדוגמה, זה זיכרון שמנוהל על ידי הגארבג' קולקטור, בגלל זה הזיכרון נקרא Managed Heap.

  3. 00:49

    Unmanaged זה אזור זיכרון שלא מנוהל על ידי הגארבג' קולקטור, וזה בדרך כלל מתייחס לזיכרון שאובייקטים שלא שייכים ל.NET יוצרים. לדוגמה, מישהו כתב איזשהו DLL בשפת C שיוצר שם איזה משהו בזיכרון.

  4. 01:08

    שום גארבג' קולקטור לא מכיר שום דבר בנוגע לזיכרון הזה. זה יהיה Unmanaged Memory, שמתבצע או שנכתב על ידי unmanaged code. אז כאן יש כמה הבדלים בין אם אנחנו מתעסקים עם resource שהוא managed לבין אם אנחנו מתעסקים ב-resource שהוא unmanaged.

  5. 01:29

    אז בואו נפתח מחלקה ראשונה שמתעסקת אך ורק עם resource שהוא managed. נקרא לה managed resource. המחלקה הזאת היא בעצם מאוד דומה לlogger שמקודם ראינו, מפני שמה שיש לנו בתוך המחלקה הזאת זה resource רק .NETי, אז בואו נפתח פה private stream writer שמצביע על איזשהו קובץ כאן

  6. 02:06

    אנחנו רואים שיש לנו מחלקה שיש לה data member שמכיל שהוא כמובן resource אבל הוא managed resource בלבד במקרה הזה אמרנו בואו נתחיל עם איזושהי פונקציה do work שעושה את העבודה אוקיי מה אנחנו עושים בתוך הפונקציה אז קודם כל אנחנו בתוך הפונקציה רוצים לבצע את העבודה

  7. 02:41

    writer.rightline פה אנחנו עובדים. מעבר לזה אנחנו צריכים לטפל בכל נושא הסגירות. מה אמרנו שאנחנו עושים? אנחנו חייבים לרשת את iDisposable לממש בפונקציית dispose אנחנו רוצים לשחרר את המשאב writer.dispose למה אני אומר שאנחנו צריכים לעשות קצת יותר מזה?

  8. 03:17

    מפני שמה שאנחנו צריכים לעשות זה כזה דבר קודם קודם כל קריאות מרובות לדיספוז לא אמורות לגרום לקריסה. אז בשביל למנוע את כל הסיפור של הקריסה מה שנעשה זה כזה דבר אחרי ששחררנו נלך ל-writer ונחניף לתוכו null בתחילה dispose נבדוק האם writer שווה ל-null

  9. 03:40

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

  10. 04:01

    לא שחררו אותך אין בעיה אני משחרר ומכניס נאל בכדי שאם יקראו לי עוד פעם אני לא אקרוס אני ממש אצא ולא אעשה שום דבר. דבר נוסף בתוך do work אנחנו צריכים לבדוק האם יש פה נאל.

  11. 04:19

    אם יש פה נאל אנחנו לא יכולים לעבוד עם האובייקט אבל אנחנו צריכים לברוק exception שנקראת object.dispose.exception ו-exception מיוחדת שקיימת בדוטנט שאומרת רגע רגע מישהו כבר עשה dispose לאובייקט שלכם יש שם איזה resource פנימי שנקרא writer ונא לא לעבוד איתו אתם לא יכולים לעבוד איתו כי

  12. 04:48

    כבר ביצעתם dispose אז אסור לכם וכאן אנחנו רואים pattern שקשור לזה שאנחנו עובדים אך ורק עם managed resource. דבר נוסף שכדאי שנוסיף זה שהפונקציה dispose תהיה וירטואלית.

  13. 05:07

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

  14. 05:25

    אז לכן במידה במידה וזה מה שקורה צריכים לקרוא לבייס נקודה דיספוז. כלומר אם אנחנו רושמים פה קלאס נקרא לזה Managed Resource Extended, היא יורשת את Managed Resource ולה יש Private Stream Writer Another Writer והיא גם רוצה לדרוס אותו אז היא לא צריכה לרשת את I-Disposable מפני שהיא

  15. 06:06

    כבר קיבלה את I-Disposable מבחוץ. כל מה שהיא צריכה לעשות זה Override על Dispose ואז לקרוא ל-Base.Dispose ואז לבצע את העניינים של השחרור שלה.

  16. 06:23

    AnotherWriter.Dispose, AnotherWriter.A-Null וכמובן עם AnotherWriter.A-Null לצאת החוצה וכמובן כל הפאטרן כמו שראינו מקודם אבל שימו לב שבגלל שהדיספוז המקורית הוגדרה כווירטואל אנחנו עכשיו כשירשנו יכולים לעשות אובר רייד ולרשת את או לדרוס את דיספוז לקרוא לבייס נקודה דיספוז זאת

  17. 07:00

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

  18. 07:30

    אז במצב הזה היא לא תהיה וירטואלית בסדר אז כל מה שעשינו כרגע זה managed resource זאת אומרת איזושהי מחלקה שיש לה אך ורק רכיב שהוא נטי בלבד שה-garbage collector יכול לשחרר אותו והוא לא קשור ל-c++ ולכן זאת השיטה שבה אנחנו משחררים.

  19. 07:55

    אבל יש עוד מקרה. מה קורה אם המחלקה שאנחנו בונים בכלל מכילה איזשהו resource שלא קשור ל-garbage collector ושקשור לאיזשהו זיכרון שהוא unmanaged וכאן יכולה להיות סכנה אחרת.

  20. 08:14

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

  21. 08:32

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

  22. 08:54

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

  23. 09:17

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

  24. 09:38

    בדרך כלל משתמשים איתו ב-C++ או ב-C ונניח שעל ההתחלה הוא מצביע על איזשהו מקום בזיכרון כלשהו. יש לנו פה פונקציה do work.

  25. 09:56

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

  26. 10:20

    אם הפוינטר שלנו שהוא בעצם unmanaged resource מכיל שום דבר נניח מכיל 0 ואומר שמישהו כבר שחרר אותו. אם הוא לא מכיל 0 אתה יכול לעבוד איתו בבקשה אנחנו עובדים עם ה-resource.

  27. 10:49

    איפה הוא אמור להכיל 0? כאשר מבצעים dispose. אנחנו צריכים לרשת את iDisposable לממש פונקציית Dispose.

  28. 11:03

    בפונקציית Dispose אנחנו מבצעים את מה שעשינו מקודם. הפונקציה תהיה virtual כמו מקודם, אלא אם כן המחלקה שלנו היא sealed כמובן.

  29. 11:13

    אם מישהו כבר שחרר לנו אותו, מישהו כבר קרא מקודם ל-Dispose,

לקורס המלא: קורס תכנות מתקדם ב‑#C ודוט-נט

ההרצאה הקודמת: Managing Resources - חלק 1

ההרצאה הבאה: תרגילים על Managing Resources

הרצאות קשורות מקורסים אחרים

  • הרצאה על Resources
  • Qualifying Resources
  • הסבר על GROUPS RESOURCES

קורסים נוספים במסלול

  • קורס WinForms - תוכנות רגילות בווינדוס
  • פרויקט מעשי ב-#C - בונים מחשבון פשוט
  • פרויקט מעשי ב-#C - ספר טלפונים
  • פרויקט מעשי ב-#C - תוכנת צייר
  • קורס ADO.NET - חיבור אתר למסד נתונים
  • קורס WCF - תקשורת למתקדמים בדוט-נט