DCSIMG
טעויות של מפתחים - Conditional Attribute vs. #IF - Bah, Humbug!

Bah, Humbug!

Wear sunscreen...

שטויות

  • Join me

בלוגים שאני קורא

טעויות של מפתחים - Conditional Attribute vs. #IF

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

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

החסרון הגדול בשימוש ב#IFים בתוך האפליקציה, היה הבלאגן שזה יצר. הקוד פתאום כלל מעבר ללוגיקה רגילה - גם לוגיקה למהדר.. והקוד הפך להיות לא קריא. מיקרוסופט באו לפתור את הדבר הזה וייצרו Attribute בשם Conditional שניתן להגדיר ברמת המטודה, ואשר יבטל את הקריאה למטודה במידה ודגל הקומפילציה הרלוונטי לא מוגדר.

אלא שיש הבדל מאוד גדול בין #IF ובין ConditionalAttribute, וחשוב שמי שבאים להשתמש בשני יכירו אותו; ConditionalAttribute לא מעלים את קטע הקוד מתוך הAssembly. הוא מעלים אך ורק את הקריאה לקוד הזה.

בתור דוגמא, נגדיר את המחלקה הבאה:

using System.Windows.Forms;
using System.Diagnostics;
 
namespace MyClass
{
    public class ConditionalClass
    {
        [Conditional("DEBUG")]
        public static void foo() 
        {
            MessageBox.Show("This is some debugging foo..");
        }
    }
}

ונגדיר את הטופס הבא שישתמש בה:

using System;
using System.Windows.Forms;
 
namespace ConditionalAttributeDemo
{
    public partial class MyForm : Form
    {
        public MyForm()
        {
            InitializeComponent();
        }
 
        private void btnClickMe_Click(object sender, EventArgs e)
        {
            // Calling our special logic..
            MyClass.ConditionalClass.foo();
        }
    }
}
 
אחרי שנעביר את שניהם קומפילציה עם דגל Debug, נראה את הIL הבא עבור MyClass.foo:
image

ועבור btnClickMe_Click נראה:

image

אם נקמפל עכשיו כRelease ונעבור על התוצרים, נראה שהMyClass.foo לא השתנה כמעט, למעט תהליך אופטימיזציה שהמהדר העביר, שהוריד את הnop בראשית המטודה:

image

 ומאידך - הbtnClickMe_Click נראה עכשיו כך:

image

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

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

using System.Windows.Forms;
using System.Diagnostics;
 
namespace MyClass
{
    public class ConditionalClass
    {
#if DEBUG
        public static void foo() 
        {
            MessageBox.Show("This is some debugging foo..");
        }
#endif
    }
}

והטופס:

using System;
using System.Windows.Forms;
 
namespace ConditionalAttributeDemo
{
    public partial class MyForm : Form
    {
        public MyForm()
        {
            InitializeComponent();
        }
 
        private void btnClickMe_Click(object sender, EventArgs e)
        {
#if DEBUG
            // Calling our special logic..
            MyClass.ConditionalClass.foo();
#endif
        }
    }
}

 ואם נסתכל על הIL (בRelease) נראה שאכן, אין אזכור לפונקציה foo:

image

ובטופס אנחנו נקבל בדיוק את מה שקיבלנו עם הConditional Attribute.

 

 

תוכן התגובה

Doron Ben-David כתב/ה:

מתנצל בפני הקוראים על היישור הגרוע של הקוד. בWLW זה היה אחלה.. דאגתי לדחוף בכל מקום DIR="RTL" וDIR="LTR"... אפילו בעורך כאן זה נראה בסדר... אבל משום מה.. זה מתחרבש בProduction כמו כל דבר :)... אם יהיה ביקוש, אני אפרסם את הSolution המפואר להורדה כZIP :)..

# November 8, 2007 12:09 AM

Bah, Humbug! כתב/ה:

הקדמה בפוסט הקודם שלי בסדרת "טעויות של מפתחים" הסברתי את ההבדל בין הConditionalAttribute לבין

# December 31, 2007 8:55 PM

Bah, Humbug! כתב/ה:

אני מזהיר מראש.. הפוסט הזה הולך לעסוק בי, דורון . הפוסט הזה הולך לעסוק באלטר-אגו שלי, הבלוג הזה. הפוסט

# May 18, 2008 11:06 AM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 6 and 4 and type the answer here:


Enter the numbers above: