לעתים קורה שאנחנו יודעים בזמן קימפול, שפונקציה מסוימת קיימת, אבל הקומפיילר לא יודע זאת.
לדוגמה, נניח שיש לנו שתי מחלקות כאלה:
|
|
ונניח שיש פונקציה שמחזירה אחת מהן:
|
|
כעת נניח שקראנו לפונקציה הזו:
|
|
ואנחנו רוצים להפעיל את הפונקציה Add. לא נוכל, מאחר ואנו לא יודעים איזה סוג אובייקט חזר, והמחלקות לא מממשות ממשק משותף.
נוכל לעשות משהו כזה:
|
|
זה יעבוד, אבל לא באמת פתרנו את הבעיה: ראשית יש לנו כאן שכפול קוד. שנית, מה אם הפונקציה GetIntegerListOrStack יכולה להחזיר לנו עוד טיפוסים עם פונקצית Add?
עד Framework 4.0 יכולנו לפתור בעיה זו רק באמצעות Reflection.
אלא שבReflection כתיבה כזאת היא לא הכי כיפית:
|
|
קריאה לפונקציה פשוטה, לקחה פה 3 שורות קוד.
בC# 4.0 נוסף Feature לשפה בשם Dynamic binding. הוא מאפשר לנו לבצע פעולה דומה לזו בסינטקס יותר כיפי:
|
|
הקוד הזה בעצם יבצע בסופו של דבר אותה פעולה – הפעלת הפונקציה Add עם הפרמטר 6.
מה קורה פה?
הdynamic הזה הוא Keyword שאומר לקומפיילר "אני יודע מה אני עושה".
עצם העובדה שיש לנו משתנה "מטיפוס dynamic", מאפשרת לנו להפעיל איזו פונקציה שאנחנו רוצים עליו.
מה שקורה בפועל זה שבזמן ריצה מתבצע חיפוש של הMemberשאני רוצה להפעיל, ובמידה והוא קיים, הוא יבצע את הקריאה אליו.
מה קורה אם הMember לא קיים? בואו ננסה:
|
|
נקבל את הException הבא:
RuntimeBinderException was unhandled: ‘IntegerList’ does not contain a definition for ‘Test’.
כלומר, נעוף בזמן ריצה, כיוון שלא קיים Member כזה.
הFeature הזה מאפשר לנו כתיבת קוד דינאמי שהוא יותר קריא, אבל לכן יש לנו יותר אחריות לשים לב שאנחנו באמת יודעים מה אנחנו עושים.
עם זאת, הFeature הזה לא מחליף לנו את Reflection באופן מלא.
אחת הסיבות היא שאנחנו יכולים לקרוא בעזרת dynamic לMemberים שהם public בלבד, ולא לכל Member של הטיפוס. (זהו גם יתרון, אבל מצד שני, לפעמים יש סיבות טובות לקרוא לMemberים שהם לא בהכרח public)
בנוסף, הדבר הזה לא מאפשר לנו לבצע ניתוח על האובייקט, למשל, לא נוכל לדעת באמצעות dynamic בלבד איזה Memberים יש לאיזשהו טיפוס, איזה Attributeים יש להם וכו’.
שבוע דינאמי טוב!