
[Serializable] מעל המחלקה. אז השמירה וטעינת הקובץ חזרה עובדות.#define עם שם מותאם, למשל TESTING.AllowMultiple מאפשרים להשתמש בו כמה פעמים על אותו איבר.Inherited = false, בלי לשלוח אותם לפי הסדר של הבנאי.GetCustomAttributes על הטיפוס ומקבלים את ה-Attributes שהוגדרו עליו.הטקסט המלא של הדקות הראשונות בהרצאה «Attributes» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
אנחנו מגיעים לנושא שנקרא Attributes. למעשה, אנחנו נתקלנו בכל מיני מקרים בנושא הזה, אבל כרגע אנחנו הולכים לראות בצורה ממש מפורטת מה קורה מאחורי הקלעים.
כאשר אנחנו אומרים Attributes, אנחנו בעצם מתכוונים ל-C-Sharp Attributes או .NET Attributes, זה בעצם הפקודות שתמיד היינו כותבים עם סוגריים מרובעים.
וכל מה שאמרנו זה שזאת איזושהי פקודה שאנחנו יכולים לכתוב מעל לקלאס או מעל לפונקציה והיא אומרת משהו למערכת. זה בגדול ההגדרה שהגדרנו עבור הפקודה הזאת.
עכשיו מה שאנחנו הולכים לראות זה מה בעצם קורה מאחורי הקלעים ואילו עוד פקודות מעניינות קיימות במערכת והאם גם אנחנו יכולים לכתוב פקודה כזאת.
אחת הפקודות הראשונות שאנחנו ראינו זאת הייתה פקודה שבעצם מגדירה שניתן לבצע סריאליזיישן על מחלקה. זאת אומרת אם לדוגמה אנחנו בונים פה איזושהי מחלקה קלאס פרסון ניקח משהו מאוד פשוט פאבליק סטרינג פול ניים.
בואו ניקח פה איזשהו קונסטרקטור מקבל פול ניים מכניס אותו וניקח כאן איזושהי פונקציית 2 סטרינג שתחזיר לנו את הפול ניים.
בעת אנחנו רוצים לקחת אובייקט פרסון, יש לנו פה פרסון, פי אחת, שווה ניו פרסון, להכניס לו כאן איזשהו שם, ואנחנו רוצים לקחת את האובייקט הזה ולשמור אותו לאיזשהו קובץ בעזרת מנגנון הסריאליזיישן.
אז קודם כל אנחנו צריכים איזשהו אובייקט שיהיה מסוגל לבצע את הסריאליזציה, לדוגמה בינארי פורמטר. לאחר מכן אנחנו רוצים שיהיה לנו אובייקט סטרים, נניח פייר סטרים, בואו ניצור קובץ, ונקרא לו, נשים אותו בכונן ה-C, נקרא לו person.binari,
ואנחנו רוצים עכשיו לגשת לפורמטר ולבצע פעולה שנקראת serialize. ניתן לה את ה-Stream, ניתן לה את אובייקט ה-Person שלנו, נסגור את ה-Stream, נריץ את התוכנית, ונחטוף את הקריסה הבאה.
יש לנו פה איזושהי קריסה, בגלל שאנחנו מריצים את זה עם קונסול אנחנו לא רואים את הקריסה הזאת, אלא אם כן נריץ את זה עם F5, ואז נראה בדיוק איפה השורה קורסת ומה בדיוק הבעיה.
ואנחנו בעצם רואים כאן שישנה בעיה שנקראת, איפה רואים את זה? הנה זה כאן. System Runtime Serialization, Serialization Exception Occured in איזשהו DLL פנימי של .NET, MScoreLib זה ה-DLL הפנימי של .NET.
הדי של ה-Information, הטיפוס person באסמבלי שלנו is not marked as serializable. ואנחנו ראינו את זה כשלמדנו על serialization, שכל מה שאנחנו צריכים לעשות בכדי שניתן יהיה לבצע את ה-serialization הזאת ולשמור את האובייקט שלנו דרך מנגנון ה-Stream, דרך מנגנון
ה-Serialization על גבי ה-Stream, זה פשוט לבוא ולתת את הפקודה serializable על ידי סוגריים מרובעים. אטריביוט. אם אנחנו עושים את זה, פתאום אנחנו רואים שהכל בסדר והמערכת מצליחה לשמור לנו את המידע לקובץ והמערכת גם יכולה לבצע את הפעולה ההפוכה.
פייל סטרים סטרים טו ריד פייל נקודה אופן טו ריד על אותו הקובץ פרסון נקודה בין ואנחנו יכולים עכשיו ללכת לפורמטר ולהגיד לו את הפעולה ההפוכה שזה ה־deserialize הנה ה־stream to read בוא תביא לנו בבקשה אובייקט פרסון p2, נסגור את ה-stream to read ונציג את הפרטים על המסך.
p2, יש לו 2-string אז הוא יוצג, נריץ את זה ואנחנו רואים שיש לנו את הפריטים ששמרנו, הקובץ קיים, הכל בסדר. איך זה יכול להיות שהפקודה הקטנה הזאתי גרמה לקריסה?
מה בעצם קרה מאחורי הקלעים ב-dotnet כאשר אנחנו מגדירים או לא מגדירים את הפקודה הזאת? אז בואו נבין מה קרה כאן. כל מה שאטריביוט מבצע, ברגע שאנחנו מגדירים אטריביוט, שזאת הפקודה הזאת עם הסוגריים המעובעים, זה סך הכל טיבת אובייקט אטריביוט, כי אטריביוט זאת מחלקה.
שימו לב שאם אני עובר על המילה serializable ולוחץ על F12, אז אני מגיע ישירות להגדרה של המחלקה הזאת. שימו לב שזאת מחלקה שמסתיימת במילה Attribute ויורשת את המחלקה Attribute, זה מה שמגדיר אותה כ-Attribute, ושימו לב שזאת מחלקה רגילה, Class.
ספציפית, המחלקה הזאת היא Sealed אבל היא לא חייבת להיות Sealed. זאת אומרת שיש לנו פה מחלקה רגילה לגמרי וכל מה שעשינו זה הגדרנו אותה על ידי סוגריים מרובעים מעל לאלמנט תכנותי במקרה הזה Class, וברגע שעשינו את הדבר הזה, כל מה שקרה זה, א', נוצר אובייקט מהמחלקה הזאת.
אנחנו יכולים אפילו לעשות פה סוגריים בצורה כזאת, וזה אומר שהפעלנו את הקונסטרקטור הריק של אותו אובייקט. זה הדבר הראשון שהתבצע.
והדבר השני שהתבצע, שהוא הדבר החשוב כאן, זה שהאובייקט הזה שנוצר נשמר, שימו לב, באזור המטא-דאטה. ולכן אנחנו יכולים עכשיו רק אחרי שעברנו והבנו מה זה Reflection ומה זה אזור המטה דאטה, רק כעת אנחנו בעצם יכולים להבין את הקונספט האמיתי של Attributes.
אז עוד פעם אני חוזר, כל מה שקרה כאן, נוצר אובייקט מהמחלקה הזאת והאובייקט נשמר באזור המטה דאטה של האסמבלי הנוכחי עבור המחלקה Person. זה קרה כאשר אנחנו הגדרנו את האטריביוט מעל המחלקה פרסון.
כאשר מבצעים סריאלייז או דה סריאלייז, כל מה שעושים במקרה הזה, כלומר פונקציית סריאלייז שנכתבה על ידי איזשהו מהנדס במייקרוסופט, כל מה שהיא עושה זה פונה לאזור המטא דאטה על ידי הכלי של הרפלקשן, טוענת את הטייפ של פרסון, ובודקת האם מישהו הגדיר לו את האטריביוט serializable.
אנחנו כמובן הולכים עוד מעט לעשות את זה בעצמנו בכדי לראות איך זה ניתן לביצוע, אבל זה כל מה שהם עשו. זאת אומרת, יש כאן שלושה גורמים שמשחקים במשחק הזה.
הגורם הראשון זה, נקרא לו מתכנת א', הוא כתב את המחלקה serializable. זה אותו מתכנת שהלך ופשוט כתב Class Serializable Attribute.
שימו לב שאם אתם כותבים מחלקה שהיא מתארת Attribute, אנחנו עוד מעט הולכים לכתוב בעצמנו אחת כזאת, אתם יכולים לסיים אותה במילה Attribute, לא חובה אבל זה יהיה הגיוני לעשות את זה, ואז כשמשתמשים במחלקה אפשר להשתמש עם המילה Attribute ואפשר בלי המילה Attribute.
זה קטע מאוד מעניין כזה שהקומפיילר מבין שאנחנו רוצים גם את זה. ולכן נהוג לסיים אותה במילה Attribute. דרך אגב, Attribute זה תכונה, איזשהו פיצ'ר או תכונה של משהו, ושימו לב שאנחנו מגדירים פה איזושהי תכונה למחלקה Person, שניתן לשמור אותה לקובץ על ידי מנגנון ה-Serilization, או ניתן להעביר אותה
דרך סטרים על ידי מנגנון ה-Serilization. אז בעצם אני חוזר לשלושת הגורמים שקיימים פה. גורם ראשון, מי שבונה את המחלקה הזאת, מתכנת א', הוא מגדיר את אותה מחלקה שמתארת את האטריביוט.
גורם ב' זה הגורם שמשתמש באטריביוט בכדי לשים אותה מעל לאיזשהו רכיב תכנותי, זה יכול להיות מעל קלאס, זה יכול להיות מעל דאטה ממבר, זה יכול להיות מעל פונקציה, זה יכול להיות בכל מיני גורמים בתוכנית עצמה.
זה יהיה מתכנת ב'. מי שבנה את המחלקה פרסון הלך והשתמש במחלקה סריה, אטריביוט בכדי להגדיר אותה מעל פרסון ולציין שהוא מרשה או מאשר להעביר אובייקט פרסון דרך סטרים בעזרת מנגנון הסריאליזיישן ואז קיים פה גורם מספר 3 נקרא לו מתכנת גימל מתכנת
גימל זה זה שכתב את פורמטר נקודה סריאליז ופורמטר נקודה דה סריאליז או אם תרצו את המחלקה הבינארי פורמטר.
מי שכתב את הפונקציה serialize אמר כזה דבר, קיים איזשהו אטריביוט שנקרא serializable. חובה להגדיר אותו מעל למחלקה שאתם רוצים שאובייקט ממנה יעבור דרך הסטרים, במידה ואתם רוצים שאני אכן אשלח אותו דרך הסטרים.
זאת אומרת, אם אתם מביאים לי איזשהו אובייקט, הנה פה הביאו לי פי אחת, אז המחלקה של האובייקט הייתה חייבת להיות מוגדרת על ידי האטריביוט הזה.
ומה שהמתכנת גימל עושה זה פשוט פעולת רפלקשן, פונה למטא דאטה, שולף משמה את הטייפ של המחלקה של האובייקט הזה שנשלח לפונקציה סריאלייז, ובעזרת רפלקשן בודק האם האטריביוט הספציפי הזה הוגדר שם.
אם לא, הוא זורק אקספצ'ן. אם כן, הוא מאשר ומבצע את פעולת ה-serialization. כנ"ל, דה-סריאלייז גם היא בעצם לא יכולה לעבוד אם לא הגדירו את האטריביוט הזה מעל המחלקה.
אז בעצם אם אנחנו מסכמים את העניין הזה, ברגע שלקחתם אטריביוט ושמתם אותו מעל לאיזשהו רכיב או קלאס או סטראקט או אינאם, לא משנה מה, כל מה שעשיתם זה שתלתם את האובייקט שנוצר פה באזור המטה-דאטה.
ומישהו אחר הולך לבצע שימוש ולקרוא את המידע הזה. אז כאן בעצם ראינו דוגמה אחת עם הקונספט של סריאליזיישן, של סריאליזבל, אבל בואו נראה עוד כמה אפשרויות או עוד כמה אטריביוטס שקיימים במערכת.
מה שנעשה זה נוציא החוצה לפונקציה שנקראת טסט סריאליזבל, נשים את זה פה ונראה עוד כמה דוגמאות. הדוגמה הבאה שאני מראה זה פשוט מאוד פונקציה שנקראת print something.
הפונקציה הזאת מדפיסה משהו. כעת אני הולך למיין וקורא ל-print something, מריץ ואני רואה שהפונקציה מתבצעת, הכל בסדר. אבל יכול להיות שהפונקציה הזאת היא דרושה לי רק עבור דיבאגינג.
נניח נקרא לה print something for debugging. זאת אומרת, אני רוצה לבצע הדפסה מסוימת רק כאשר אני מבצע דיבאגינג או נמצא במחשב הפיתוח או כרגע מפתח את האפליקציה שלי וברגע שאני משחרר גרסה ללקוח אני לא רוצה להדפיס את הדבר הזה כי הוא לא קשור ללקוח
הוא קשור רק אליי לצורכי דיבאגינג אז ראינו בעבר את הדגל הזה שיש כאן דיבאג וריליס אם אני נמצא במחשב הפיתוח אז הרבה פעמים אני מגדיר שאני נמצא במוד שנקרא דיבאג במצב דיבאג אם אני משחרר גרסה ללקוח שנייה לפני שאני מבצע את הקומפילציה האחרונה או לפני שאני בונה ערכת התקנה אני
מעביר את זה ל-release ושיניתי פה מצב ועכשיו כל המערכת פועלת כאילו במצב ריליס אני יכול לבדוק את זה בכל מיני מקומות בתוך התוכנה שלנו ולפי זה להגדיר כל מיני הגדרות נניח במצב דיבאג אני פונה לקובץ שנמצא אצלי במחשב בנתיב א' במצב ריליס אני פונה לקובץ ב' שנמצא אצל הלקוח בנתיב ב'
אז אם אני נמצא במצב דיבאג אני כן רוצה להריץ את הפונקציה, אם אני נמצא במצב ריליס אני לא רוצה. איך אני מציין את זה?
כל מה שאנחנו צריכים לעשות זה להבין שיש כמעט לכל דבר פקודת אטריביוט. כאן אנחנו משתמשים באטריביוט שנקרא conditional, ופה אנחנו צריכים להגדיר לו את המוד הזה.
שימו לב, יש רק מוד שנקרא דיבאג, אין מוד שנקרא ריליס, או שאנחנו מגדירים את זה על דיבאג או שאנחנו לא מגדירים בכלל. אז אם אנחנו מגדירים בדיבאג זה אומר שרק אם אנחנו במוד של דיבאג הפונקציה הזאתי אמורה להתבצע.
בואו נריץ את זה ונראה שהפונקציה אכן מתבצעת. אוקיי, עכשיו אני משחרר גרסה ללקוח, שנייה לפני שאני עושה את זה אני מעביר את זה ל-release, נריץ, ושימו לב שאני לא במצב דיבאג והפונקציה בכלל לא התבצעה.
נחמד. אבל מה קורה אם אני רוצה לבצע פונקציה אחרת לא קשורה למצב דיבאג או ריליס? אם קורה איזה משהו נניח עבור בדיקות מסוימות אז אני רוצה לבצע את הפעילות הזאת ואני יכול להגדיר לעצמי איזשהו דגל אחר לדוגמה טסטינג זה לא חייב להיות עם אותיות גדולות אבל זה מקובל אז הנה יש לנו פה איזשהו דגל טסטינג אוקיי נקרא לפונקציה print
something for testing ניפטר רגע מהדיבאג נריץ ונראה שבעצם זה לא מוצג מה זה בדיוק טסטינג אז אנחנו