198. XName mystery

לפני כמה זמן תכנתתי לי במה שנקרא Linq To XML, זו ספרייה שהגיעה בFramework 3.5 יחד עם Linq המאפשרת לעבוד בצורה יחסית נוחה עם XMLים.

יצרתי לעצמי איזשהו Element:

1
XElement myElement = new XElement(XName.Get("FirstElement"));

ויצרתי לו מספר Attributes ומספר בנים:

1
2
3
4
5
myElement.Add(new XAttribute(XName.Get("FirstAttribute"), 3));
myElement.Add(new XAttribute(XName.Get("SecondAttribute"), 3));
myElement.Add(new XElement(XName.Get("FirstChild")));
myElement.Add(new XElement("AnotherChild"));
myElement.Add(new XElement(XName.Get("YetAnotherChild")));

קימפלתי וראיתי שהכל מתקמפל. אחר כך שמתי לב שקרה פה משהו מוזר – כל הOverloadים של הConstructorים של XElement וXAttribute מקבלים משהו שנקרא XName.

אלא שבאחת הקריאות (הקריאה האחת לפני האחרונה) לא העברתי לConstructor את הטיפוס הזה, אלא מחרוזת רגילה, כי שכחתי לקרוא לXName.Get.

מה שמדהים בכל הסיפור הזה זה שזה מתקמפל.

התחלתי לחקור את הסיפור:

אולי יש Constructor שלא ראיתי? חיפשתי וחיפשתי ולא מצאתי. אז אולי יש Extension method שיכול לקבל string במקום לקבל XName?

לא יכול להיות דבר כזה, כי אין Extension methods לConstructorים..

בקיצור, המשכתי לחפש. אולי אני טועה, אולי התוכנה לא באמת מתקמפלת? אלא שבדקתי והתוכנה כן מתקמפלת.

מה שהיה ממש מוזר בכל הסיפור הזה, זה שכשעשיתי Go to definition לConstructor הזה, הוא הביא אותי לConstructor שמצפה לקבל XName, כלומר לאותו Constructor שביצעתי קריאה אליו בשורות הקודמות.

אחרי כמה זמן של חיפושים ומחשבות הגעתי לתשובה – קיים Implicit cast בין XName לstring!

1
public static implicit operator XName(string expandedName)

אחרי שגיליתי שהוא קיים, אני מאוד שמח שהוא קיים, כיוון שהוא חוסך כתיבה. אלא שהיה נחמד אם היה יותר קל לזהות את זה.

שימו לב שאם אתם כותבים implicit casts משלכם, שזה לא גלוי לעין שיש הסבה כזאת.

כשקוראים קוד שמשתמש בהסבות כאלה, לא רואים הכל, ועד לדיבוג אפשר לחשוב שמבינים את כל הקוד, אבל בעצם מתבצעת פה קריאה לפונקציה, באופן נסתר מהעין. כדאי לשקול זאת בשימוש.

המשך יום בלי הרבה תעלומות טוב

שתף