
T כטיפוס כללי. מתכנת שבונה את המחלקה לא יודע עדיין מה הטיפוס, ומתכנת שמשתמש במחלקה קובע אותו כשהוא יוצר אובייקט.הטקסט המלא של הדקות הראשונות בהרצאה «Generics - חלק 1» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
אנחנו מגיעים לנושא מאוד בסיסי ולכן גם מאוד חשוב שנקרא ג'נריקס. מה זה ג'נריק? ג'נריק זה בעצם היכולת שלנו בתכנות להגדיר איזשהו משתנה שהטיפוס שלו אינו מוגדר באופן ספציפי בזמן יצירת המשתנה אלא מוגדר לאחר מכן.
תכף אנחנו נראה מה הכוונה אבל קודם כל בואו לצורך ההבנה של החומר הזה נתחיל עם דוגמה פשוטה. בואו נניח שאנחנו רוצים ליצור איזושהי מחלקה או איזשהו פרויקט שמאפשרת לנו לתאר הודעת sms.
בואו נקרא לפרויקט הזה sms message. בואו נפתח את הפרויקט, ואנחנו רוצים ליצור איזושהי מחלקה שמתארת sms שניתן לשלוח. אז בואו ניגש לפרויקט ונוסיף לעצמנו new class, נקרא לקלאס הזאת sms וכעת בואו נחשוב מה בעצם צריך להיות בתוך הקלאס כdata member.
אז כאשר אנחנו שולחים sms בואו נניח שאנחנו רוצים כרגע שיהיה לנו פשוט מאוד את ההודעה עצמה שאנחנו מעוניינים לשלוח ולכן אנחנו יוצרים פה איזשהו משתנה עבור ההודעה.
אז אנחנו יודעים שהודעת sms זה בדרך כלל סטרינג אז בואו נגדיר סטרינג, ויש לנו כרגע מחלקה שמתארת אס.אם.אס עם איזשהו מסאג'.
אבל בואו נניח שלפי הספסיפיקציות שלנו הודעה שניתן לשלוח באס.אם.אס זה לאו דווקא סטרינג. אנחנו יכולים לשלוח באס.אם.אס גם לדוגמת תמונה, ואולי מבחינת תכנות אנחנו רוצים שיהיה לנו פה את הגמישות לשלוח גם משתנה מסוג דייט טיים אם אנחנו רוצים לשלוח אס.אם.אס שמתאר את השעה ואת התאריך, או משתמש מסוג תו אם אנחנו רוצים לשלוח רק
תו או מספר שלם או מספר עשרוני. כלומר בוא נניח שמבחינת האפיון שלנו אנחנו רוצים שניתן יהיה לשלוח sms והמסאג' ההודעה עצמה לא מוגדרת רק כסטרינג אלא צריכה להיות כל דבר.
כל מה שמתכנת ב' ירצה לשלוח מבחינת טיפוס נתונים אנחנו נרצה שהוא יוכל לשלוח במסאג'. אז כמובן במקרה כזה סטרינג כבר לא מתאים לי. אוקיי, אז מה אנחנו כן יכולים להגדיר מבחינת .NET?
אנחנו יכולים להגדיר את מחלקת הבסיס Object. בואו נעשה את זה. בואו נניח שאנחנו רוצים לשלוח כל דבר בתור מסאג', אז יש לנו מחלקה sms, יש לנו data member מסוג Object שנקרא מסאג'.
בואו נסגור פה את ה-Solution Explorer, נשים את שתי הקבצים האלה, את הפרוגרם ואת ה-sms side by side, ונגדיר אפילו, בואו נגדיר איזשהו סיטור ריק, סיטור מלא, שמקבל ליתר דיוק אובג'קט, מסאג' ומגדיר מסאג' שווה מסאג'.
בואו נבנה פה עוד איזושהי פונקציה, send, שמקבלת נניח איזשהו טלפון, ומציגה sending the message to the טלפון. ואנחנו רוצים לבדוק את זה.
כל מה שאנחנו צריכים לעשות זה ליצור אובייקט, אנחנו יכולים לפנות לקונסטרקטור שלו ולהגיד הודעה ראשונה זה hello sms.send לאיזשהו טלפון בואו נקרא לזה sms אחד וה sms הראשון שאנחנו שולחים ויש לנו פה sms שני שאנחנו בכלל לא רוצים לשלוח את המחוזת הלו אלא date time.now ואפילו sms שלישי שאנחנו רוצים לשלוח איזשהו
מספר sms. חסרוני כלשהו. 1, 2, נקודה, 3, 4, כולם לאותו טלפון בוא נניח, נריץ ונראה שמבחינה תכנותית אין פה שום בעיה, הכל בסדר.
אבל בואו טיפה נחשוב יותר לעומק אם מה שעשינו זה הדבר הכי נכון. איך הגדרנו את המסאג'? הגדרנו את המסאג' על ידי טיפוס הנתונים הבסיסי Object, וברגע שעשינו את זה אז כמובן יכלנו לשלוח כל דבר.
אנחנו רואים שאנחנו יכולים לשלוח כל מיני טיפוסים. היינו יכולים לא בהכרח להפעיל את הקונסטרקטור המלא, אלא לפנות ל-smf2.message ולהכניס לתוכו את כל הערכים שאנחנו רוצים שיהיו בו בצורה כזאת, ועדיין זה היה עובד כמו שצריך.
אבל למעשה, כאשר אנחנו עובדים עם אובג'קט כמחלקה אובג'קט, יש לנו פה מספר חסרונות שמאוד כדאי לנו להבין מה הם ולמה לא כדאי לנו לעבוד עם המחלקה Object וכדאי לנו למצוא פתרונות אחרים.
אז בואו נסתכל מה בדיוק החסרונות שקיימים במחלקה Object. בואו נניח שבנינו את ה-SMS בצורה הזאת, ועכשיו בואו נניח שאנחנו מעוניינים לשלוח כל מיני הודעות מכל מיני סוגים שונים, אבל אנחנו לא מעוניינים שיכניסו כל דבר לתוך המסג'.
לדוגמה, אם מישהו הולך ובונה איזושהי מחלקה, בואו ניקח Class Person, ויש לו Public, String, Full Name, או בואו נתחיל עם First Name, ויש לו Public, String, Last Name, ועכשיו ניתן לגשת, לבנות איזשהו אס.אם.אס אחר
ולשלוח להודעה שלו אובייקט מסוג פרסון. אם אנחנו נלך למסג', אנחנו רואים שאנחנו יכולים לפתוח אובייקט פרסון חדש לגמרי, וזה יהיה ממש בסדר מבחינת המערכת.
שימו לב שכמובן הוא יציג לנו פה את ה-sms-message.person בתור המשתנה שאנחנו שולחים, ויכול להיות מצב שזה לא באמת משהו שהוא נדרש או משהו שהוא נכון לביצוע על ידי התוכנית שלנו.
מה שאני מנסה להגיד זה שברגע שהשתמשתם עם Object, אמרתם לעצמכם שאתם יכולים לשלוח כל דבר. ובזה שאתם מאפשרים לשלוח כל דבר זה גמישות יתר.
אז יכול להיות שהגמישות יתר הזאת שמאפשרת לכם לשלוח מה שאתם רוצים ולהכניס מה שאתם רוצים לתוך המשתנה message היא לא טובה לכם. יכול להיות שאתם רוצים ליצור איזשהו אס-אם-אס, וספציפית את האס-אם-אס הזה להגביל אותו רק למחרוזות שונות, ואת האס-אם-אס הזה להגביל רק למספרים, אבל אתם לא רוצים לאפשר בשום מקרה לאף אחד
לשלוח פרסון. אז קודם כל, זאת בעצם איזושהי בעיה מסוימת שקיימת וזה הגמישות יתר. בעיה נוספת שקיימת לנו כאשר אנחנו עובדים עם אובג'קט, זה שאין לנו אינטליסנס, בואו ניקח את הדוגמה הזאת.
יכול להיות מצב ששלחתי פה את המסאג' שהוא daytime.now ומיד לאחר מכן אני רוצה לפנות ל-sms2. ואני יודע שהמסאג' שלנו זה אובייקט מטיפוס daytime.
אם אני לוחץ עכשיו נקודה אני לא מקבל את כל מה שקיים לי ב-daytime כאשר אם הטיפוס הזה אכן היה daytime שימו לב איזה מידע הייתי מקבל באינטליסנס. לדוגמה את העיר.
אני לא יכול עכשיו לבוא לפה ולהגיד אני רוצה לגשת ישירות ל-eer זאת אומרת מה שאני מנסה להגיד שהחיסרון הזה בעצם אומר אין לנו IntelliSense אם אנחנו עובדים עם Object אפילו שהכנסנו אובייקטים ספציפיים.
החיסרון השלישי זה חיסרון שבא לפצות על החיסרון השני והוא אומר אין בעיה שתיכנסו ל-eer או שתגיעו ל-eer על ידי קאסטינג אתם רוצים להגיע ל-eer תעשו קאסטינג ל-day time בצורה כזאת.
וברגע שעשיתם קאסטינג ל-day time הגעתם ל-year. זאת אומרת אם היינו מראש מגדירים את המסג' בתור day time גם היה לנו IntelliSense וגם לא היינו צריכים לעשות קאסטינג.
במידה ועבדנו עם אובייקט אין לנו IntelliSense ולכן אנחנו צריכים לעשות קאסטינג. כלומר IntelliSense היה מאפשר לנו לראות איזה דברים קיימים ולגשת אליהם ישירות.
ברגע שזה אובייקט אז כמובן אנחנו לא נהנים מה IntelliSense וגם אם אנחנו רוצים לגשת ישירות למה שבאמת קיים שמה, עלינו להשתמש בקאסטינג, וזה די כאב ראש בשביל המתכנת.
החיסרון הרביעי שקיים לנו באובג'קט זה חיסרון שקשור לעולם היעילות. לצורך החיסרון הזה, בואו נסתכל בדוגמה נפרדת על עיקרון מאוד חשוב שקיים בדוטנט.
לצורך כך בואו שנייה נסגור את הדוגמה הקודמת ואנחנו כמובן הולכים לחזור אליה, ונפתח דוגמה חדשה שהיא לא חלק מהדוגמה הקודמת בכדי להבהיר את הרעיון.
כל התרגילים האלה כמובן יהיו נגישים לכם ותוכלו להוריד אותם ביחד עם כל החומר. אוקיי, מה שאני רוצה להדגים עכשיו זה עיקרון בדוטנט שנקרא Boxing and Unboxing.
עיקרון מאוד חשוב שמאוד חשוב להבין מה הוא אומר. Boxing זה בעצם פעולה שמתבצעת על ידי דוטנט. ומה הפעולה הזאת אומרת? נניח שיש לכם איזשהו משתנה אינטג'רי, נקרא לו num.
נכניס אליו איזשהו מספר לדוגמה 100. כעת ניקח אובייקט מטיפוס אובייקט. ליתר דיוק זהו לא אובייקט אלא רפרנס ונכניס לתוך הרפרנס הזה את num.
בגלל שאנחנו יודעים שכל דבר או כל טיפוס בדוטנט יורש את אובייקט, אז אין לנו שום בעיה לקחת רפרנס של אובייקט ולהכניס לתוכו.
כל משתנה שהוא אז אנחנו רואים שהintelli sense או ליתר דיוק שהקומפיילר לא צועק עלינו ואם אנחנו עכשיו ניגש ונציג גם את num וגם את obj יש לנו פה את num יש לנו את obj אנחנו נוכל לראות שיש לנו גם 100 ב-num וגם כמובן ב-obj הולך להיות לנו 100 והכל בסדר אבל מה שאנחנו לא רואים פה זה מה באמת קרה בזיכרון וקודם כל אנחנו צריכים להבין אינטג'ר זה סטראקט אם
אנחנו נכנסים בעזרת f12 לתוך אינטג'ר אנחנו כמובן מגיעים למחלקה אינט 32 שהיא מתארת לנו את אינטג'ר ואינט זה בעצם אינט 32 ואנחנו רואים שזה סטראקט ואנחנו יודעים כבר ממודול האובג'קט אוריינטד שסטראקט יוצר לנו משהו שנקרא value type ולמעשה החוק בדוט נט אומר שאובג'קט שזה קלאס והיא מחלקת הבסיס של כל המחלקות
לא מסוגלת להצביע ישירות על value type. מה באמת קורה כאן? Object לא מסוגל להצביע על value type בצורה ישירה. ה-value type הספציפי הזה בכלל קיים באזור זיכרון שנקרא Stack segment.
כל המשתנים הלוקאליים נפתחים ב-Stack segment. אובייקטים נפתחים ב-heap, ב-managed heap, אזור זיכרון שמיועד לאובייקטים.
Object מסוגל להצביע רק על אובייקטים שקיימים ב-heap, ולכן הוא לא מסוגל להצביע על הנם הזה שבכלל נמצא לנו בסטאק סגננט.
אז מה קורה בדוטנט? בדוטנט קורית פעולה שנקראת בוקסינג, ומה שדוטנט מבצעת זה יוצרת לנו אובייקט חדש, רק בגלל ההשמה הזאת נוצר אובייקט חדש ב-manage the heap, והאובייקט הזה מחזיק שני חלקים, מכיל בעצם שני חלקים.