פעם שעברה ראינו שהפונקציה GetMethod יודעת למצוא את הOverload שהכי מתאים לסוגי הפרמטרים שאנחנו מעבירים לה.
אני רוצה להסביר קצת על איך הפונקציה הזאת עובדת, כי זה יכול לעזור לנו לכתוב דברים דומים:
אם נסתכל בReflector נופנה להרבה פונקציות. בסופו של הדבר הפונקציה המעניינת היא הפונקציה
|
|
של RuntimeType.
אם נסתכל עליה נראה שבסופו של דבר היא משתמשת במשהו שנקרא Binder כדי למצוא את המתודה המתאימה ביותר.
מה זה Binder?
אם נזכר בטיפים על Reflection (מספרים 136-151), אמרנו שמה שקורה בזמן קריאה לפונקציה בעזרת Reflection, הוא מיפוי של האובייקטים שאנחנו שולחים לפונקציה לפרמטרים שלה, באמצעות תהליך שנקרא Late Binding.
Binder הוא בעצם מנגנון שמאפשר לנו לשנות את המיפוי הזה.
ממה הוא מורכב?
הוא מכיל את הפונקציות הבאות:
|
|
מה אנחנו רואים כאן? לFieldInfo וMethodBaseשהכרנו מReflection יש בעצם איזושהי פונקציה מתאימה שעושה לנו את הBinding אליו.
בנוסף, יש פה פונקציה מעניינת שנקראת ChangeType הנקראת בעת קריאה למתודה (בעזרת Invoke), ומאפשרת לנו להשפיע על איך אובייקט ישלח לפונקציה שלנו.
מה שאותנו מעניין הוא דווקא הפונקציה
|
|
הפונקציה הזאת מקבלת חתימה מערך של מתודות ומערך של טיפוסים, ומחפשת מבין כל המתודות את המתודה הכי מתאימה לחיפושים. זה עושה עבודה שמזכירה את העבודה שעושה הקומפיילר בזמן קימפול כדי למצוא את הOverload הכי מתאים לפרמטרים שהעברנו למתודה. אם אין כזה היא זורקת AmbiguousMatchException.
אם נסתכל בפונקציה GetMethodImpl, נראה שבעצם מה שהיא עושה זה קוראת לSelectMethod עם הטיפוסים שהיא קיבלה ועם מערך של כל המתודות שיש לטיפוס עם שם מסוים.
למה עוד זה שימושי? אני אכתוב שימוש שהיה לנו עם זה:
יש לנו מחלקה שיכולה לקבל כל מיני סוגים של הודעות כInput.
המשתמש יכול לטפל בהודעות מסוג מסוים במתודה משלו ע"י כתיבת מתודה בודדת והשמה של Attribute מסוים מעליה:
|
|
ברגע שמגיעה הודעה היא יודעת להגיע למתודה (הבודדת) המתאימה.
בהתחלה זה מומש ע"י החזקה של Dictionary שממפה טיפוסים למתודות, ואז מפנה למתודה המתאימה ע"י חיפוש הGetType של האובייקט בDictionary.
אבל זה לא עבד. למה לא עבד? כי אם נניח הייתה לי חתימה כזאת:
|
|
אז זה לעולם לא היה נכנס אליה, כיוון שאין Instance שהטיפוס הקונקרטי שלו הוא Shape.
ככה למשל לTriangle וSquare לא היה שום טיפוס שיש לו מתודה מתאימה במחלקה שלי.
אפשר לחשוב על איך לממש משהו שישווה Typeים עפ"י עדיפות וימצא את הType הכי מתאים לType שהתקבל, אלא שזה קצת מסובך לממש דבר כזה…
במקום זאת, אפשר להשתמש בBinder שבא עם הFramework שימצא את המתודה עם החתימה הכי מתאימה! 😃
אלו מכם שינסו ליצור instance של Binder, יתאכזבו לשמוע שזו מחלקה אבסטרקטית, ושכל המימושים שלה בFramework הם internal (טיפ מספר 213).
מסתבר שאפשר להשתמש במימוש הדיפולטי ע"י גישה לProperty הסטטי Type.DefaultBinder.
סופ"ש מעולה שלא כבול לשום דבר.