DCSIMG
Know When to Use The "as" Keyword - Liran Chen's Blog

Liran Chen's Blog

.Net Internals, Debugging, Multithreading - and More!

Know When to Use The "as" Keyword

ב-#C יש 2 דרכים לביצוע cast בין טיפוסים.
הראשונה היא הדרך הסטנדרטית והמוכרת:


class Person { }

class Program

{

static void Main()

{

object foo = new Person();

Person bar = (Person)foo;

}

}


ולעומתה, השימוש במילת המפתח "as":

object foo = new Person();

Person bar = foo as Person;


ההבדלים
  • ניסיון לבצע קאסט "סטנדרטי" על טיפוסים שאין ביניהם קשר של הורשה/מימוש (למשל ניסיון לבצע קאסט בין מחלקת Car לבין Apple), יוביל לזריקת שגיאה מסוג InvalidCastException.
  • לעומת זאת, ניסיון לבצע קאסט בלתי אפשרי באמצעות שימוש במילת המפתח "as" לא יגרום לזריקת שגיאה. בסך הכל מה שיקרה זה שהפעולה תחזיר null, והתוכנית תמשיך בביצוע כרגיל.
  • אם רוצים להיות מעט פדנטים, אז מבחינת ביצועים, "as" הינה מעט פחות מהירה מאשר שימוש בקאסט רגיל.
הבעיה
למתכנתים רבים יש נטייה להשתמש ב-"as" במקומות לא נכונים.
מהו מקום "לא נכון"? כל מקום בו הטיפוס שאנו מבצעים עליו את הקאסט (foo) חייב להיות מהטיפוס שעליו אנו מנסים לבצע את הקאסט (Person). שלמעשה, מדובר בערך ב-95% מהמקרים.
הרי נניח ופעולת הקאסט נכשלה. בשימוש ב-as, המשתנה שלנו יתאתחל ל-null והתוכנית תמשיך לרוץ כרגיל. רק "מאוחר יותר", בפעם הראשונה שמישהו ינסה לגשת למשתנה הזה, תתעופף שגיאת NullReferenceException שכנראה לא תגיד לנו שום דבר שלא קשור לקאסט שנכשל לפני 200 שורות קוד.
לעומת זאת, אם היינו משתמשים בקאסט הרגיל, כבר על ההתחלה היתה נזרקת לנו שגיאת InvalidCastException שהיתה מספקת לנו את כל המידע הדרוש להבנה מלאה למה שהוביל לשגיאה.
האלטרנטיבה (והשימוש הנכון) ב-as הוא לבדוק האם הקאסט הצליח על ידי השוואה ל-null. אבל מן הסתם, לא נרצה לכתוב את הקוד המעייף הזה בכל פעם שאנו מבצעים קאסט כזה או אחר.

אז מהו "המקום הנכון"?
בכל מקום בה קיימת אפשרות אמיתית והגיונית שהמופע עליו אנו מנסים לבצע את הקאסט באמת לא שייך לטיפוס הנכון. ומאוד הגיוני שהקאסט יכשל.
במקרה כזה, אין סיבה לזרוק שגיאה מאחר ואנו מצפים ומקבלים את העובדה שיתכן שהקאסט יכשל. לכן במצב כזה עלינו לבדוק אם הקאסט בכלל הצליח.
דוגמה למצב כזה היא מימוש לפונקציית ה-Equals. כשאנו דורסים אותה, אנו מקבלים פרמטר מסוג object, כך שלפני שאנו נגשים להשוואת הערכים בין שני המופעים, אנו בכלל לא יודעים באיזה טיפוס מדובר..
שימוש בקאסט רגיל כאן הוא לא נכון, כי יתכן שמישהו העביר כפרמטר מופע של טיפוס לא מתאים ... עלינו לצפות למקרה כזה, ו..."להתנהג בהתאם".



public override bool Equals(object obj)

{

Person other = obj as Person; // use 'as' to cast obj to Person

bool result = Equals(other); // call IEquatable<Person>

 

return result;

}


תוכן התגובה

אודי מילוא כתב/ה:

www.codeproject.com/.../csharpcasts.aspx

נא לקרוא את ההשוואות שהבחור הזה עשה.

לפי הגרף שלו, AS היא הדרך הטובה ביותר מבחינת ביצועים, עדיפה בסדר גודל על המתחרה.

יש עוד משהו אחד ששווה לזכור אם משתמשים הרבה ב AS.

מאחר והוא יכול להחזיר NULL, אין אפשרות להשתמש בו במקומות שהם לא NULLABLE כמו ENUM לדוגמא.

יום שמח!

# May 21, 2009 10:07 AM

spiritus asper כתב/ה:

פקטור הביצועים רחוק מלהיות משמעותי כאן.

אם הגעת למצב שאתה עושה אופטמיזציות לסוגי קאסטינג בשביל לשפר ביצועים .. אתה עושה משהו לא נכון :)

הרבה יותר חשוב מההבדל של העוד כמה מיקרו-שניות האלה הוא הנכונות של הקוד שלך

# May 21, 2009 4:19 PM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 5 and 3 and type the answer here:


Enter the numbers above: