
Dispose על אובייקט Context, ומה קורה כשהקוד קורס באמצע? ההרצאה מראה את הבעיה ואת הפתרון באמצעות try-finally ואחר כך using.DbContext, ולכן יש לו Dispose. התפקיד שלה לשחרר משאבים, כמו חיבור לדאטאבייס שנפתח. בסיום העבודה חובה לקרוא לה, אחרת נשארים משאבים פתוחים, בזבוז ואיטיות.try-catch אחת ברמה גבוהה תופסת חריגות, אבל אם יש קריסה באמצע, הקריאה ל-Dispose שבסוף לא מתבצעת. להדגמה יוצרים חלוקה באפס (1 / a כש-a = 0), והודעת ה-disposing לא מוצגת.try-finally: מצהירים על המשתנה מחוץ ל-try, מאתחלים אותו בפנים וקוראים ל-db.Dispose() ב-finally. הבלוק finally מתבצע תמיד, עם חריגה או בלי, והחריגה ממשיכה למעלה ונתפסת שם. בלי קריסה ועם קריסה, הודעת ה-disposing מוצגת.using: יש יותר מדי קוד בשיטה הקודמת, ולכן using (var db = new GiftShopContext()) { ... } עושה את אותו הדבר מאחורי הקלעים: קורא ל-Dispose בסיום הבלוק, בתוך try-finally. אין צורך לכתוב את ה-Dispose בעצמכם.using בלי בלוק: בגרסה חדשה של C# כותבים using GiftShopContext db = new(); ללא סוגריים מסולסלים, בלי הזחה נוספת. ה-Dispose נקרא בסוף ה-scope של המשתנה.using, כי היא לא חלק מה-finally הסמוי.using.הטקסט המלא של הדקות הראשונות בהרצאה «שחרור משאבים - using» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
כשאנחנו ניגשים לדאטאבייס אנחנו עושים את זה על ידי אובייקט הקונטקסט. אובייקט הקונטקסט יורש מחלקה שנקראת db-context. אחד מהדברים שיש למחלקה הזאת זאת פונקציה dispose.
ברגע שאנחנו יורשים מחלקה שיש לה dispose אז כאילו גם לנו יש dispose. מה זה dispose? אז אנחנו עושים תזכורת קלה. dispose זה פונקציה מאוד מאוד חשובה שהתפקיד שלה זה לשחרר משאבים.
לדוגמה המערכת פותחת איזשהו קישור לדאטאבייס ואנחנו רוצים לסגור את הקישור לדאטאבייס או כל מיני משאבים אחרים שהמערכת עובדת איתם פנימית. ברגע שאנחנו עובדים עם אובייקט ב-dotnet שבנוי ממחלקה שיש לה dispose, לא משנה אם היא הרשה את זה או שהיא בונה את זה בתוכה, אנחנו צריכים בסיום העבודה לקרוא לפונקציית
dispose. זאת נקודה מאוד מאוד חשובה, אחרת יהיו לנו פה אפשרויות של פתיחת resources מבלי לסגור אותם, מה שיוביל כמובן לבזבוז משאבים, פרפורמנס אישו, אולי איטיות.
כל מה שאנחנו כאילו צריכים לעשות זה בסיום העבודה עם הקונטקסט שלנו לקרוא ל-dispose. אם אנחנו מריצים את זה אנחנו אמורים לראות שהמערכת עובדת אותו הדבר והכל נראה בסדר. אבל זה לא באמת בסדר.
למה? כי הרבה פעמים קורה שכאשר אנחנו ניגשים למצד נתונים אנחנו רוצים להגן מפני גריסות שזה הגיוני לגמרי. יכול להיות שאנחנו עושים איזושהי שאילתא למסד הנתונים, שהשאילתא לא הגיונית מבחינת הדאטאבייס.
זה לא המצב כרגע, אבל זה כמובן יכול להיות. במצב כזה הדאטאבייס פשוט זורק חריגה, מקריס לנו. אנחנו יודעים שברגע שאנחנו ניגשים לדאטאבייס מאוד מאוד חשוב לבצע טרייקאץ'.
אז אנחנו יכולים לעטוף את הקוד הזה בטרייקאץ', אנחנו יכולים לעטוף כאן בטרייקאץ' בשביל לתפוס כל מיני קריאות לפונקציות. בואו נניח שאנחנו עוטפים את הקוד הזה ב-trycatch.
אז אני הולך לכאן למיין ועוטף את כל הקטע קוד הזה, בוא נגיד כאן, ב-trycatch. יש לנו פה exception, error, בצורה כזאת.
מה בעצם אנחנו רוצים לעשות? אנחנו רוצים להציג איזה ERR message נניח, ויש לנו כאילו הגנה מפני קריסות. למה זה רע? זה לא רע. בואו רגע נעשה איזשהו דמו של קריסה.
אנחנו הלכנו והבאנו את המידע מהדאטה בייס, ובואו נניח שלא הצלחנו להביא אותו כי רצינו להביא משהו לא הגיוני, בגלל שהפקודה הזאת לא באמת קורסת, נעשה פה הדמיה לקריסה.
נניח אני יוצר פה איזה משתנה int a שווה 0 ויוצר b שווה 1 חלקי a. הדבר הזה יגרום לקריסה. חלקי אפס המערכת לא תצליח לבצע את זה כי מבחינתה b זה אינטג'ר ואינטג'ר לא יכול להחזיק חלוקה באפס שזה תיאורטית אינסוף אז הדבר הזה יקרוס וזה כאילו אנחנו עושים פה עוד הבעיה כאילו השורה הזאת קרסה זה לא באמת משנה איזה שורה קרסה מה שמעניין אותי שבאזור הזה יש קריסה
כאילו שהקריסה היא פה מה יקרה אם יש קריסה אנחנו מנסים לבצע טרייקאץ' כאילו לתפוס את הקריסה על ידי קאץ' אין פה טרייקאץ' ואני לא רוצה שיהיה פה טרייקאץ' מפני שיש לי פה את ההגנה, זה ממש בסדר. כלומר, התוכנית לא באמת תקרוס כי תפסנו את הקריסה פה.
ואז הוא יגיד לנו איזושהי שגיאה והכל בסדר. בואו נריץ, הוא לא יבצע שום קריסה, attempt to divide by zero זה לא קריסה, זאת הצגה של החריגה שהתבצעה. מה שקרה, התוכנית כאן בעצם התבצעה חריגה, חיפשה קאץ' טריי קאץ' בתוך הפונקציה, לא מצאה, יצאה לכאן ונתפסה פה.
המערכת בסופו של דבר לא קרסה. אבל האם הפקודה dispose התבצעה? אם אני אשים כאן איזה הוראה על המסך, הדפסה על המסך, disposing.
האם אנחנו נראה את ההדפסה disposing? תשובה ממש לא. בואו נריץ את זה. attempt to divide by 0, אין disposing. כן יצרנו אובייקט קונטקסט, כן ניגשנו לדאטאבייס, כן יש פה ריסורסז שהמערכת יצרה וכאשר המערכת קורסת איפשהו היא לא תגיע לדיספורז שנמצא בסוף.
חשוב להבין, אני לא רוצה כאן לכתוב טרייק אט שזה לא שאני לא יכול או אסור, מותר, אבל הרבה פעמים קורה שאני רוצה באיזשהו היי-לבל מסוים לטפל בכל הגריסות.
טיפול אחד ויחיד אני לא רוצה בכל פונקציה יכול להיות שפה הולך להיות לי פה הרבה פונקציות שניגשות לטאטאפייס אני לא רוצה בכל אחת מהן להתחיל לבצע טיפול בבעיות וטיפול כמובן זה catch אז איך אנחנו מטפלים בבעיה הזאת שאם הקוד קורס לנו עדיין אנחנו רוצים לקרוא לדיספוז אז יש בעצם מספר טיפולים לדבר הזה בואו נראה אותם טיפול ראשון אומר
כזה דבר אנחנו לא יוצרים קאץ׳ אנחנו יוצרים טריי פיינלי. מה זה הדבר הזה? זה קצת, שוב, זה תזכורת לגבי C-Sharp, מותר לבצע טריי קאץ׳, מותר לבצע טריי קאץ׳ פיינלי ומותר לבצע רק טריי פיינלי. טריי פיינלי אומר, תשמע, אין לי פה קאץ׳ אז אם תהיה חריגה אני לא יכול לטפל בה, אני אמשיך לגלגל אותה למעלה
אבל אני כן לבצע את מה שכתוב ב-finally מבלי לטפל בחריגה. זאת אומרת שאם מישהו מלמעלה יותר תופס אותה היא באמת תיתפס אצלו ולא אצלי כי אני לא רוצה לטפל פה בחריגה, אני לא רוצה להתחיל להציג קאצ'ים פה.
מה אני רוצה לבצע ב-finally כמובן את ה-dispose, ה-finally מה שיפה בו זה שהוא תמיד תמיד מתבצע בין אם לא הייתה חריגה בין אם כן הייתה חריגה.
אז כל מה שאנחנו עושים זה מביאים לפה את ה-finally את ה-db-dispose הוא כמובן לא מכיר אותו, אנחנו צריכים לקחת את הדבר הזה ולייצר כאן משתנה ממנו בואו נניח נאפס אותו ל-null ואז אנחנו יודעים שיש בתוכו איזשהו קטע קוד נגיד שבוודאות אני הולך להכניס לתוך משהו הנה יצרתי בתוכו את האובייקט ואז בוודאות אני יודע שכאן
יש אובייקט אם אין קריסה אנחנו נגיע לאזור של הדיספוזינג אם אם יש קריסה אנחנו גם נגיע לאזור של הדיספוזינג. בואו נריץ את זה מבלי לקרוס ונראה שהדיספוזינג מתבצע.
שימו לב, הנה הדיספוזינג. בואו נריץ את זה עם קריסה ואז זה לא יתבצע, ההדפסה לא תתבצע של המתנות כי הייתה פה קריסה אבל הדיספוזינג כן יתבצע.
אז אם אנחנו מריצים את זה, הנה אנחנו רואים דיספוזינג שנייה לפני היציאה מהפונקציה הוא מתבצע. ו-attempt to divide by zero כי זה נתפס גם כאן, שזה בדיוק מה שאני רוצה.
דיזיין הזה שאני יוצר פה את האובייקט של הקונטקסט, עושה טראי, פה מייצר אובייקט ממנו, פה כמובן לא יוצר אובייקט אלא רק רפרנס, יוצר אובייקט בתוך הטראי, וב-finally קורא לדיספוז, זה בעצם הבסיס לאיך אנחנו תמיד תמיד תמיד קוראים לדיספוז.
עכשיו מגיעה פה בעיה אחרת, זה too much code. זה כאב ראש, מה זה כל הקוד הזה, אני אישית לא אוהב לכתוב כל כך הרבה קוד. אז .NET באה ואומרת לנו, בגלל שהדבר הזה הוא כל כך נפוץ, כל כך הרבה מקומות יש מצב שבו אתם רוצים בוודאות לקרוא ל-dispose, בין אם הייתה חריגה ובין אם לא,
אני אתן לכם מילה שמורה שעושה מאחורי הקלעים את ה-try-finally. שוב, לא try-catch-finally, כי היא לא יודעת לטפל בקריסות מבחינתנו, אלא רק try-finally.
הקוד הזה זה מה שהמערכת הופכת בסופו של דבר, את הקיצור. והקיצור אומר כזה דבר. יוזינג. לא להתבלבל בין היוזינג שלפעמים כתוב למעלה לבין היוזינג שלנו.
יוזינג זה בלוק, בתוכו אני יכול לבנות אובי אקט. gift shop context db=new. אני פותח פה בלוק, סוגר בלוק, ומה שדוטנט עושה זה בוודאות הולכת וקוראת לדיספוז פה בסוף ברגע שאנחנו יוצאים מהבלוק, לא רק זה, היא שמה את זה בתוך טריי פיינלי מאחורי הקלעים.
בואו נשלים רגע את הקוד הזה, אני לא צריך