DCSIMG
Force a switch block to implement all cases (using FxCop) - שלמה גולדברג (הרב דוטנט)

שלמה גולדברג (הרב דוטנט)

מרצה בסלע ויועץ בעולם ה - net.

Force a switch block to implement all cases (using FxCop)

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

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

אז אחרי שהתבכיינתי, נגש לעניין.

 

באחד הפוסטים הראשונים כתבתי על דרך להכריח את המתכנתים כשעושים switch על enum, לעשות case על כל האפשריות, ו Arielr כתב בתגובה "לא יהיה יותר קל לכתוב חוק של FXCOP ולסגור עניין?" אז חשבתי לעצמי, קדימה בוא נממש את זה, אז נכנסתי לעולם של FxCop, וממשתי את זה.

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

נסתכל על הקוד הבא:

 

    1 [ForceSwitch]

    2 public enum MyEnum

    3 {

    4     A, B, C, D, E

    5 }

    6 

    7 public class Class1

    8 {

    9     public Class1(MyEnum myEnum)

   10     {

   11         switch (myEnum)

   12         {

   13             case MyEnum.C:

   14                 Console.WriteLine("");

   15                 break;

   16             case MyEnum.B:

   17                 Console.WriteLine("");

   18                 break;

   19             default:

   20                 Console.WriteLine("");

   21                 break;

   22         }

   23     }

   24 }

 
אנחנו רואים enum שיש עליו attribute בשם ForceSwitch ויש class שב ctor שלו אנחנו עושים switch על ה enum,
כשנקמפל, נקבל את השגיאה הבאה:
 
Switch
 
הקוד שלנו יעבור קומפילציה, רק אם נממש case עבור כל אחד מהאפשרויות.
 
 
לפני שנראה את המימוש הספציפי, נעשה מעבר קטן על FxCop,
למעשה זה נותן לנו את היכולת לשלוט על איך יראה הקוד שלנו, החל משליטה על סגנון שמות של מאפיינים (שכולם יתחילו באות גדולה) עד להגדרות של Code Security, למעשה יחד עם Visual Studio מגיע סט מכובד של חוקים שיכולים לעזור לנו לכתוב יותר נכון.
לחיצה ימנית על הפרויקט, לחיצה על מאפיינים, ובחירה בטאב של Code Analysis יביא אותנו למסך הבא:
 
Code Analysis
 
כמו שאחנו רואים בתמונה יש לנו מבחר של חוקים שאנחנו יכולים לבחור בהם, כדי להכריח את המפתחים לכתוב נכון, ואנחנו יכולים להוסיף חוקים משלנו, כמו זה שאחנו רואים בתמונה שמסומן (הקידומת של SG, ראשי תיבות של שמי)
 
אפשר כמובן להגדיר האם זה שגיאה או אזהרה, על ידי סימון האפשרות מצד ימין של כל חוק, ואפשר להגדיר האם זה ירוץ אוטומטי בכל קומפילציה, על ידי סימון האפשרות Enable Code Analysus on Build, במדה וזה לא יהיה מוגדר, כשנרצה להריץ את הבדיקות, לחיצה ימנית על הפרויקט, ואז Run Code Analysis.
 
כעת נראה כיצד אנחנו יכולים להוסיף חוקים בעצמנו.
אז בשלב ראשון אנחנו נירש מ class שנקרא BaseIntrospectionRule ונצטרך להוסיף reference לשני ה dll הבאים:
  • C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\FxCopSdk.dll
  • C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\Microsoft.Cci.dll
כעת נראה את הקוד:
 

    1 internal class ForceSwitch : BaseIntrospectionRule

    2 {

    3     public ForceSwitch()

    4         : base("ForceSwitch",

    5                 "SGFxCopRules.SGFxCopRules.xml",

    6                 typeof(ForceSwitch).Assembly)

    7     { }

    8 

    9     public override ProblemCollection Check(Member member)

   10     {

   11         Method method = member as Method;

   12         if (method != null)

   13         {

   14             VisitMethod(method);

   15         }

   16 

   17         if (Problems.Count == 0)

   18         {

   19             return base.Check(member);

   20         }

   21 

   22         return Problems;

   23     }

   24 

   25     public override void VisitSwitchInstruction(SwitchInstruction switchInstruction)

   26     {

   27         TypeNode enumType = switchInstruction.Expression.Type;

   28         foreach (var item in enumType.Attributes)

   29         {

   30             if (item.Type.Name.Name == "ForceSwitchAttribute")

   31             {

   32                 if (switchInstruction.Targets.Count != enumType.Members.Count - 1)

   33                 {

   34                     Resolution resolution =

   35                         GetResolution(new string[]

   36             {

   37                 enumType.Name.Name

   38             });

   39 

   40                     Problems.Add(

   41                         new Problem(resolution,

   42                                     switchInstruction.SourceContext));

   43                 }

   44             }

   45         }

   46     }

   47 }

 
 
 
הקוד הוא מאוד פשוט:
הוא מורכב מ:
Ctor: שקורא לאבא שלו, ושולח לו את הפרמטרים הבאים: השם שלו, היכן ממוקם ה xml (נראה אותו בהמשך) שמגדיר את החוק, וחייב להיות מוגדר כ Embedded Resource.
override Check : אנחנו נבדוק האם אותו member הוא מתודה, במידה וכן נפעיל את Visit, שבמדה והוא ימצא בלוק של switch, הוא יפעיל אוטומטית את ה -
VisitSwitchInstruction : שבודק האם יש על ה enum הזה attribute בשם ForceSwitch, במדה וכן הוא יבדוק האם לא מימשו את כל ה cases האפשריים, ובמדה וכן, הוא יוסיף Problem למאגר,
ה - Problem מורכב מ Resolution שיש לו מחרוזת שתכנס בהודעת השגיאה כמו שמוגדר ב xml (שכבר נראה אותו) ומ - SourceContext שיודע איפה בדיוק (שורה, וכדומה) התרחשה השגיאה.
 
ה xml נראה כך:
 

    1 <Rules FriendlyName="SGFxCopRules">

    2   <Rule TypeName="ForceSwitch" Category="SGRules" CheckId="SGR1000">

    3     <Name>ForceSwitch</Name>

    4     <Description>You must implement all cases in the enum</Description>

    5     <LongDescription></LongDescription>

    6     <Owner/>

    7     <Url>/ForceSwitch</Url>

    8     <Resolution>Not all enum '{0}' cases were implented</Resolution>

    9     <Email/>

   10     <MessageLevel Certainty="99">Error</MessageLevel>

   11     <FixCategories>NonBreaking</FixCategories>

   12   </Rule>

   13 </Rules>

 
בשורה 1 מגדירים מה יהיה כתוב בחלון של Code Analysis על הקטוגריה שלנו.
אחרי זה אנחנו מגדירים סט של מאפיינים עבור ה rule, ובשורה מספר 8 אנחנו מגדירים את הודעת השגיאה, וכמובן ה 0 יוחלף עם הפרמטרים שאנחנו שולחים מהקוד.
 
וכמובן כך נראה ה attribute
 

    1     public class ForceSwitchAttribute : Attribute

    2     {

    3 

    4     }

 
כמובן שהוא לא צריך לעשות כלום, הוא בסך הכל צריך לסמן את ה enum, אפשר לקרוא לזה MarkedAttribute.
 
 את הקוד המקומפל צריך לזרוק ל
:C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\Rules
 
 
אני מצרף את הקוד יחד עם קוד לבדיקה, להורדה מכאן.
 
והנה מספר לינקים:
 
FxCop
 
Code Analiysy
 
Code Analysis Team Blog
 
ומצגת נחמדה שמסבירהה בצורה פשוטה על FxCop (אני התחלתי בזה)
 
תהנו
 
בפוסט הבא, אני אספר לכם, איך אפשר לדבג את הקוד של ה Code Analisys.

 

 

תוכן התגובה

Baruch Frei כתב/ה:

כל הכבוד על ההשקעה. באמת התפלאתי למה לקח כ"כ הרבה זמן...

אבל היה שוה לחכות.

# December 19, 2008 2:32 PM

Rotem Bloom כתב/ה:

לגבי העניין שכתבת בהתחלה שה-PUBLISH נמחק לך. פשוט תשתמש ב-LIVE WRITER במקום להשתמש ב-IE שאתה כותב פוסט.

get.live.com/.../overview

הרבה יותר נוח יעיל ואפשר לשמור הכל על המחשב שלך.

# December 19, 2008 8:09 PM

Maor David-Pur כתב/ה:

שלמה, פוסט מעולה!!!

זה אמור להיות אחד הפוסטים הבאים שלי כי הבטחתי לקהל אצלי בהרצאה ב DEV ACADEMY שאפרסם כזה פוסט.

כל הכבוד על ההשקעה והשיתוף.

מאור

# December 19, 2008 8:16 PM

Avi Pinto כתב/ה:

שימושי ביותר, תודה

# December 19, 2008 10:52 PM

Abugov כתב/ה:

אחלה!

# December 20, 2008 1:04 PM

שלמה גולדברג כתב/ה:

אז כמו שהבטחתי, בסוף הפוסט הקודם , הפוסט הנוכחי ידגים איך אפשר לדבג קוד של Code Analysis שאנחנו כותבים

# December 20, 2008 8:41 PM

Shlomo כתב/ה:

רותם, תודה על ה Live Writer, זה מאוד עוזר

# December 20, 2008 8:46 PM

Moshe כתב/ה:

באיזו גרסה אתה משתמש (VS?)

משום מה אצלי גם לאחר התקנת FxCop אין לשונית "Code Analisis"

# December 21, 2008 11:16 AM

Shlomo כתב/ה:

זה קיים כבר ב Visual Studio 2005

זה יותר משנה, איזה סוג פרויקט יש לך, אם יש לך פרויקט מסוע Web Site, אז אין באמת טאב של Code Analysis

רק אם תבחר ב

Propery Page->Build->Enable Code Analysis

# December 21, 2008 11:44 AM

שלמה גולדברג כתב/ה:

טוב, כנראה החוויה הקשה שעברתי עם מחיקת הפוסט של ה FxCop בזמן publish, לא עוזבת אותי, כי אני ממשיך לכתוב

# December 21, 2008 3:10 PM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 6 and 7 and type the answer here:


Enter the numbers above: