מדי פעם כשאנחנו כותבים קוד, אנחנו נתקלים בבעיה הנפוצה הבאה:
מדי פעם אנחנו כותבים פונקציה שמחזירה Value type, כגון int, long, bool וכו’.
לפעמים אנחנו רוצים להחזיר ערך המעיד על כך שהתבצעה שגיאה (קלט לא תקין למשל).
אפשרות אחת היא לזרוק exception, אבל זו אפשרות פחות מוצלחת, מאחר וexceptionים אינם אמורים להיות חלק מהflow של האפליקציה.
אפשרות שנייה היא להחזיר ערך “לא תקין” המעיד על כך שקיבלנו ערך לא תקין.
למשל, הפונקציה IndexOf של string מחזירה ערך -1 כאשר לא נמצא אינדקס מתאים לערך המבוקש.
הבעיה עם הפתרון הזה היא שאין מוסכמה של מהו ערך תקין ומהו ערך לא תקין, כלומר מישהו יכול להחליט שהערך -1 מעיד על ערך החזר לא תקין, ומישהו אחר יכול להחליט שדווקא 0 מעיד על שגיאה.
היינו רוצים להחזיר ערך קבוע שמעיד על שגיאה. כאשר אנחנו עובדים עם Reference types אנחנו יכולים תמיד להחזיר null.
לצערנו (ולפעמים אנחנו גם מודים על כך), אנחנו לא יכולים להחזיר null כאשר ערך ההחזר הוא value type.
בframework 2.0 המציאו פתרון. שמו הוא Nullable types.
במקום לכתוב פונקציה כזאת:
|
|
נוכל להחליף את ערך ההחזר להיות Nullable<int> ולהחזיר null במקרה שקיבלנו ערך לא תקין:
|
|
יש syntactic sugar שעשו בשפה, כדי שנוכל לכתוב במקום Nullable<int> פשוט int?:
|
|
קריאה לפונקציה תראה כעת כך:
|
|
או כך:
|
|
במקום כך:
|
|
נסביר קצת על Nullable<T>:
זהו value type (struct) שעוטף value typeים אחרים. יש implicit cast מT הנעטף לNullable<T>.
כלומר נוכל לכתוב קוד מהסגנון
|
|
בנוסף הוא "יכול לקבל" ערך null.
למה "יכול לקבל" בגרשיים? באופן כללי value typeים לא יכולים לקבל null.
כשאנחנו כותבים שורה כזאת:
|
|
הקומפיילר מקמפל אותה למשהו כזה:
|
|
שזה שקול לכתיבה:
|
|
לכן nullable types כמו כל value type לא באמת מקבלים את הערך null.
לכן נוכל לגשת ללא חשש לProperty שנקרא HasValue.
עם זאת, השוואה לnull והצבת null מתרגמים מאחורי הקלעים לפעולות על הProperty HasValue, ולכן נוכל לכתוב בצורה האינטואיטיבית שהזכרתי מעלה.
סופ"ש כבר לא גנרי מצוין