DCSIMG
December 2008 - Posts - שלמה גולדברג (הרב דוטנט)

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

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

December 2008 - Posts

נכון שה CAPTCHA באתר הוא סתם לעצבן את המגיבים ? לקרוא ולא להאמין

 

אחד מהתחביבים שלי, זה לבדוק security של אתרים, אתם יודעים אפילו דברים פשוטים כמו xss, Sql Injection ועוד.
לפני כמה ימים רציתי להוריד את קובץ ה css של האתר, כדי לראות איזה classes אני צריך לדרוס אם אני רוצה לשנות את המראה של הבלוג שלי כמו שגיא כתב כאן.
אז כשהסתכלתי על ה source של האתר ראיתי שם של פונקצייה ב java script שמיד הדליק לי את כל נורות האזהרה, אז חבשתי את כובע ההקאר שלי והתחלתי להסתכל על הקוד,
 
לפני שנתחיל, שווה שנייה להבין למה צריך CAPTCHA, לכאורה הסבה העיקרית היא שלא לאפשר למתכנתים לכתוב קוד שימלא את האתר בספאם, או לדוגמא באתר של בזק, אחרי שמבקשים חמשה שמות צריך להקליד את ה CAPTCHA, שם זה כדי למנוע ממתכנתים לכתוב תוכנה שתסרוק את האתר שלהם ותעשה חיפוש הפוך (לפי מספרי טלפון, נניח),
 
אז בואו נראה את הפונקציה שהקפיצה אותי.
 
אז הנה הפונקצייה לפניכם:
 
function ValidateCaptcha(val, args)
{
    var value = args.Value;
    var nameEQ = "CAPTCHA=";
    var captchaNumbers;
    var ca = document.cookie.split(';');
 
    for (var i = 0; i < ca.length; i++)
    {
        var c = ca[i];
        while (c.charAt(0) == ' ')
        {
            c = c.substring(1, c.length);
        }
 
       if (c.indexOf(nameEQ) == 0)
       {
            captchaNumbers = c.substring(nameEQ.length, c.length);
       }
    }
 
args.IsValid = captchaNumbers == value;
}
 
אז מה אנחנו רואים, שלמעשה הבדיקה מתבצעת בצד הקליינט, ואיך יודעים מה המספרים שבתמונה, זה נשמר ב cookie,
ישר אני פותח את ה Fiddler כדי לראות, מתי נשמרה cookie, ואז אני רואה שאכן בתוך ה html  של כל פוסט יש הפנייה לדף http://blogs.microsoft.co.il/blogs/adir_ron/archive/captcha.ashx
 
שלמעשה זה התמונה, ובזמן הטעינה שלו הוא שומר ב cookie את המספר.
 
אם אני הייתי באמת הקאר, הייתי ממש נעלב, כאילו מה עבר למתכנת בראש כשהוא כתב את הקוד הזה,
למעשה גיא אמר לי שכבר פורסם פוסטים בנושא, אז חפשתי ובאמת מצאתי כמה פוסטים שמדברים בערך על הנושא, גם Dotmad ציין כאן שלפעמים אי אפשר להגיב ואוהד ענה שצריך לעשות reload לתמונה, עכשיו זה ברור למה זה עובד, מכיון שה cookie נטעון שוב.
 
אז אם כבר דיברו על הנושא, למה אני בכל זאת מדבר על זה שוב, כי כשקצת חקרתי יותר לעומק, גיליתי דבר מדהים. רק המשתמש המסכן בדפדפן צריך להקיש את המספרים, אם אתה ספאמר שמנסה לגשת מקוד, אתה לא צריך אפילו להתאמץ לקרוא את ה cookie, ומדוע, כי למעשה זה validator, שמקושר על הלחצן, שלפני שנגשים לשרת, לבדוק האם המספרים מתאימים, אבל אם אני נגש דרך HttpWebRequest או אפילו דרך WebClient, אני לא עובר את הבדיקה, כי לא לחצתי על שום לחצן,
 
ולכן אני אומר שה CAPTCHA זה נטו כדי לעצבן את המגיבים, ואין לזה שום תועלת לגבי ספאם.
 
ואם זה לא היה עצוב זה היה מצחיק.
 
נ.ב. לפני שפרסמתי את הפוסט שאלתי את מיכל האם זה בסדר לפרסם פוסט בנושא הזה, (אולי ספמארים יקפצו על המציאה)
אז היא ענתה לי, שזה נתון להחלטתי, אבל מומלץ שאם אני מפרסם שאני קודם יפנה את השאלה ל COMMUNITY SERVER לראות האם הם מודעים לזה או לא,
אז שלחתי אליהם את השאלה, והנה התשובה שלהם, לעיונכם:
 

 
Hi Shlomo,
Yes, that site is definitely using our software, however out of the box Community Server does not use that captcha system, and it was not added by Telligent. We also do not manage that site, so I'm afraid I can't assist you a whole lot with this issue :-(

Thanks,
Ryan Howard

 
בכל מקרה החלטתי לא להדגים איך כותבים את הקוד של הוספת תגובות מקוד.
Posted: Dec 30 2008, 07:54 PM by Shlomo | with 5 comment(s)
תגים:,

באג באתר: חייבים לעשות Sign Out באתר הבלוגים אם אתם לא על המחשב שלכם

 

יוצא לי הרבה פעמים להתחבר לאתר של הבלוגים לא מהמחשב שלי, ואם אני רוצה להכנס ל control panel, אני צריך לעשות Sign In,
אז כמובן שאני מוריד את הסימון מ Next time automatically sing me in, ורק אז אני נכנס.
 
למרבה הפלא מתברר שהאתר מתעלם איכשהו מהורדת הסימון,
ואחרי שעשיתם Sign In ממחשב כלשהו, אז כל עוד שלא תעשו Sign Out, הוא יזכור אתכם ויכנס באופן אוטמטי ללא צורך בזיהוי.
 
 
Posted: Dec 29 2008, 11:58 AM by Shlomo | with no comments
תגים:

למה לא לעבור ל Internet Explorer 8

 

ביום רביעי שעבר התקנתי את Internet Explorer 8 וביום ראשון הזה הסרתי אותו.
 
אז לפני שאספר את הסיבה שהסרתי, אני דווקא רוצה לדבר בשבחו,
היו לו שני דברים שמאוד התלהבתי.
1, כשהקלדתי בשורת הכתובת את ה URL, הוא הביא לי רשימה של URL פנימיים שהייתי בהם, לדוגמא, אם התחלתי להקליד את הכתובת של הבלוג, הוא הביא לי את ה URL של לכתוב פוסט חדש.
2, בשלב כלשהו היו פתוחים שני טאבים, ואחד מהם בחר להתרסק, ולפני שהספקתי למצמץ, הטאב שוחזר אוטומטית.
 
אז כמובן שכל אוהדי פיירפוקס והחיות האחרות למיניהם, יקפצו ויגידו "אצלנו זה כבר קיים שנים" וכו',
אז כדאי שתבינו שרוב האנשים שלא עוברים מ IE למתחרים זה בגלל שהם התרגלו, אני למשל מאוד אוהב להתנסות בטכנולוגיות חדשות, אני אעבור ראשון לכל גרסה של Visual Studio שתצא, אבל אני לא עברתי ל Vista ולא עברתי ל Office 2007, בדיוק מאותה סיבה שאני לא אעבור מ IE, אני לא אוהב שמשנים לי את סביבת העבודה שהתרגלתי לעבוד בה, אפילו שזה יותר נוח, ויש יותר פיצ'רים, וזאת לדעתי הסבה של רוב האנשים שמכירים כמה סוגי דפדפנים ונשארים ב IE.
 
אז למה באמת לא נשארתי ב IE8,
זה לא בגלל שכל פעם שניסיתי לבחור באופציית ה preview באתר הבלוגים כדי לראות איך נראה הפוסט שכתבתי, ה IE החליט להתרסק עם access violation, שזה דרך אגב אחד הבאגים הגרועים ביותר, ב Visual Studio הבא עלינו לטובה, החליטו שכברירת מחדל, שגיאות מהסוג הזה לא ניתנות לתפיסה על ידי בלוק של try..catch.
גם לא חזרתי בגלל בעיות אבטחה למיניהם, למשל ניסיון לשנות frame.location מחלון אחר היא בעיית אבטחה שכבר ידועה הרבה זמן, ותוקנה בגרסה 7 למשל, ואיכשהו חזרה לגרסה 8.
 
אני מניח שאם הייתי משחק עוד כמה ימים עם IE8, הייתי מגלה עוד רשימה של באגים נחמדים, אתם יודעים בטא וכל זה.
 
הסבה שחזרתי ל IE7, הייתה פשוטה. במייקרוסופט החליטו שאם אתה משתמש בגרסה שמונה, אסור לך להשתמש בגרסה שבע, וזה לא מקובל עלי,
אין לי בעייה להוריד את 8 ולשחק עם זה ובכל פעם שזה מתרסק, לשלוח לכם דו"ח, אבל בחייכם, למה אי אפשר שיהיה לי שני IE על המחשב, בדיוק כמו שיש (לא לי) גם פיירפוקס וגם IE.
 
אז זאת הסבה שחזרתי אחורה, ואני לא ממליץ לאף אחד לעבור כרגע לגרסה 8.

לכותבי הפוסטים בעברית (Internet Explorer - AddIn)

 

הבעייה בלכתוב פוסטים בעברית היא ידועה, אז נכון שמי שמשתמש עם ה Live Writer, החיים שלו הרבה יותר קלים, אבל עדיין יש הרבה בלוגרים (אני בתוכם, ואל תשאלו אותי למה) שכותבים את הפוסטים באתר, אז כדי לכתוב בעברית ובאנגלית (קוד) באותו פוסט, צריך לעבור את התהליך המעצבן הבא.
 
ללחוץ על הלחצן html בסרגל כלים,
לחכות 30 שניות עד שהדף יגמור להטען,
להוסיף: div dir=rtl align=right, (או להפך באנגלית),
וללחוץ על update.
 
נשמע פשוט, לא ?
 
אז כשאתם עושים את זה הרבה פעמים, זה כבר מתחיל לעצבן, ויותר גרוע, הרבה פעמים יוצא keft במקום left, ואתם מגלים את זה רק בסוף אחרי שעשיתם publish כי ה preview לא יודע שעשיתם טעות, כי מבחינתו מספיק ltr כדי להפוך צד.
 
בקיצר, זה מאוד מעצבן.
 
אז ביום רביעי שעבר, החלטתי שזהו, חייבת להיות דרך שתפתור לי את הבעייה, התחלתי לחפש איך מוסיפים AddIn ל Internet Explorer,
חפשתי וחפשתי, וכל הזמן הגעתי רק לתוצאות של חברות מסחריות, שכותבים Templete ל Visual Studio, שאפשר לייצר דרכו AddIn,
 
כמובן שלא התכוונתי להשקיע 150$ במוצר שלהם אז המשכתי לחפש, וביאושי הוספתי את מילות הקסם (לא יודע למה לא עשיתי את זה קודם) CodeProject, כמובן שמיד הגעתי לתוצאה המבוקשת, העתקתי משם את הקוד, ושיניתי אותו כדי שיתאים למה שאנחנו צריכים.
 
אחרי שתתקינו את ה AddIn הזה, (אחרי שתחלצו, זה נמצא תחת BlogDirectionInstaller\Debug) שכתבתי, תקבלו בלחיצה ימנית על העכבר (מחוץ לתיבת הטקסט שבו כותבים את הפוסט) שני תוספות נחמדות. (יש מצב שאתם צריכים לסגור את כל ה browsers)
 
 
AddIn Pic
 
כמו שאתם רואים, נוספו שני לחצנים, אחד לכתיבה באנגלית, והשני לכתיבה בעברית,
לחיצה על כל אחד מהם תוסיף בסוף ה html את ה div המתאים.
(תזכרו שהעכבר יכול להיות בכל מקום באתר, אבל מחוץ לתיבת הטקסט שבו עורכים את הפוסט)
 
------------------------------
 
למעשה התלבטתי האם להוסיף בפוסט הזה גם את כל ההסברים הטכניים, או להשאיר את זה לפוסט אחר, בסוף הפוסט הנוכחי ניצח, וזה הסבה שבניגוד להרגלי, הפוסט מופיע גם בקטגוריית פיתוח וגם במומחי מיחשוב.
 
טוב, אז לפני שנראה מה ה Installer עושה, ואיך מוסיפים AddIn, נראה מה רץ ברקע כשאנחנו לוחצים על אחד משני התוספות,
 
אז כמובן שרץ script כלשהו, שהנה הוא לפניכם:
 
<SCRIPT LANGUAGE = "JavaScript">
    // Get the window object where the context menu was opened.
    var oWindow = window.external.menuArguments;
 
    // Get the document object exposed through oWindow.
    var oDocument = oWindow.document;
    if(oDocument.URL == http://blogs.microsoft.co.il/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost)
    {
        for(var i = 0; i < oDocument.frames.length; i++)
        {
             var editor = oDocument.frames[i];
             if(editor.document.URL == 'http://blogs.microsoft.co.il/tiny_mce/jscripts/tiny_mce/blank.htm')
             {
                 var docEditor = editor.document;
                 var divHeb = '<div dir = "rtl" align = "right">&nbsp;</div>';
                 docEditor.body.innerHTML = docEditor.body.innerHTML + divHeb;
                 break;
             }
         }
     }
 </SCRIPT>
 
 
(נורא מעצבן שאין את ה Copy As Html גם עבור דפי html)
 
הנה ההסברים:
בהתחלה אנחנו מקבלים reference אל ה window שבו נפתח ה Contex Menu.
לאחריו, אנחנו מקבלים reference אל ה document שלו.
אנחנו בודקים האם האתר שבו אנחנו נמצאים, הוא האתר של הבלוגים והדף הנוכחי הוא הדך שבו כותבים פוסטים חדשים. (לפי ה url)
אנחנו רצים בלולאה על כל ה frames של הדף.
במדה וכן, אנחנו בודקים האם ה document של ה frame הוא העורך של ה html.
אם מצאנו אותו, אנחנו מוסיפים ל body את ה div המתאים (ב script הנוכחי, לעברית)
 
כמובן שברגע שהאחראי על האתר ישנה את הקוד של האתר, זה יכול להיות שינוי שמות של urls, או שינוי של frames, ה addin יפסיק לעבוד)
 
 
אחרי שהבנו, מה הסקריפט שרץ ברקע, נראה איך מקנפגים שהוא ירוץ.
אז כל המידע נמצא כאן.
בגדול ב - registry תחת: HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt
אתם מוסיפים key שהשם שלו יופיע ב context menu, וב data של ה default כותבים את המיקום של הקובץ שבו נמצא הסקריפט שלנו.
 
 
 ונעבור גם על הקוד של ה Installer.
(הבטחתי כבר לפני חודש לגיא בורשטיין שאני אכתוב מאמר על ה Installer של Visual Studio, אבל זה עדיין לא מוכן, בתקווה שהוא יהיה מוכן בקרוב, ולכן לא אעבור על כל הקונספט של ה Installer).
 
בלינק שנתתי למעלה, יש את כל הקוד של ה AddIn, שמכיל שני פרויקטים, פרויקט אחד של ה Installer שמעתיק את שני קבצי ה Html שמכילים את הסקריפטים שראינו למעלה, ומריץ את הקוד של הפרויקט השני (הוא מריץ את זה כי זה מוגדר ב Custom Action של ה Installer, כשהמאמר על ה Installer יהיה מוכן, אני מבטיח להוסיף לינק).
 
הקוד שרץ בזמן ההתקנה נראה כך:
 

    1 public override void Install(IDictionary stateSaver)

    2 {

    3     base.Install(stateSaver);

    4     //grab the target director and add to install.installstate

    5     stateSaver.Add("TargetDir", Context.Parameters["DP_TargetDir"]);

    6 }

    7 

    8 public override void Commit(IDictionary savedState)

    9 {

   10     base.Commit(savedState);

   11 

   12     string targetDir = savedState["TargetDir"].ToString();

   13 

   14     AddToRegistry(Path.Combine(targetDir, "DirectionHeb.html"),

   15                   "Microsoft Blog - Direction Hebrew");

   16 

   17     AddToRegistry(Path.Combine(targetDir, "DirectionEng.html"),

   18                   "Microsoft Blog - Direction English");

   19 }

   20 

   21 private void AddToRegistry(string file, string title)

   22 {

   23     try

   24     {

   25         RegistryKey key;

   26         string regPath = @"SOFTWARE\Microsoft\Internet Explorer\MenuExt\ ";

   27         string subKey = regPath + title;

   28 

   29         key = Registry.CurrentUser.CreateSubKey(subKey);

   30         key.SetValue(null, string.Format("file://{0}", file));

   31 

   32         key.Close();

   33     }

   34     catch (Exception ex)

   35     {

   36        MessageBox.Show(ex.Message);

   37     }

   38 }

   39 

   40 protected override void OnBeforeUninstall(IDictionary savedState)

   41 {

   42     base.OnBeforeUninstall(savedState);

   43 

   44     //removing items from the context menu of IE

   45     string subKeyHeb = @"SOFTWARE\Microsoft\Internet Explorer\MenuExt\

   46                         Microsoft Blog - Direction Hebrew";

   47 

   48     string subKeyEng = @"SOFTWARE\Microsoft\Internet Explorer\MenuExt\

   49                         Microsoft Blog - Direction English";

   50 

   51     try

   52     {

   53         Registry.CurrentUser.DeleteSubKey(subKeyHeb);

   54     }

   55     catch { }

   56 

   57     try

   58     {

   59         Registry.CurrentUser.DeleteSubKey(subKeyEng);

   60     }

   61     catch { }

   62 }

 
במתודה Install, אנחנו שומרים את ה path שנשלח כפרמטר מההתקנה.
במתודה Commit, אנחנו מוסיפים ל registry, את שני הערכים החדשים, כל פעם מפעילים את המתודה AddToRegistry שמקבלת את המיקום של הקובץ, והשם שיופיע ב Context Menu
ובמתודה OnBeforeUninstall, מנסים להסיר את הרישום ב registry.
 
טוב, אז אני מקווה שעשיתי לכותבי הפוסטים בעברית חיים יותר קלים.
ותהנו.

Changing the value of the process priority (Part 2)

בפוסט הקודם דברנו על איך לשנות עדיפות של process,

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

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

 

    1 void RunProcess(string proName)

    2 {

    3     Process myProcess = new Process();

    4     myProcess.StartInfo.FileName = proName;

    5     myProcess.Start();

    6     Thread.Sleep(1000);

    7     myProcess.PriorityClass = ProcessPriorityClass.High;

    8 }

 
לפני שנמשיך, רק אזכיר שעומר הציע לשנות את העדיפות לפני שמפעילים את ה process, אבל זה לא עובד מכיון שאם מנסים לעשות את זה, מקבלים exception.
 
הבעייה בדוגמא עם השהיית ה thread, היא כמו שאריאל כתב, "ואם לפרוסס לוקח יותר משניה לעלות אז הקוד שוב לא עובד"
 
הדוגמא של רותם היא יותר טובה, ומה שהוא מציע, זה לעבוד בשיטת ה polling, להפעיל מישהו אחר ברקע שכל עוד שהעדיפות לא השתנתה, הוא מנסה לשנות, והקוד יראה כך:
 

    1 void RunProcess(string proName)

    2 {

    3     Process myProcess = new Process();

    4     myProcess.StartInfo.FileName = proName;

    5     myProcess.Start();

    6 

    7     Action action = () =>

    8         {

    9             while (myProcess.BasePriority == 8)

   10             {

   11                 myProcess.PriorityClass = ProcessPriorityClass.High;

   12                 myProcess = Process.GetProcessById(myProcess.Id);

   13                 Console.WriteLine(myProcess.PriorityClass.ToString());

   14                 Console.WriteLine(myProcess.BasePriority);

   15                 Thread.Sleep(100);

   16             }

   17         };

   18 

   19     action();

   20 }

 
הסבר:
השורות הראשונות הם זהות, אנחנו מייצרים process, ומריצים אותו,
בשורה 7 עד 19, יש לנו Action, שמיד נסביר, ובסוף אנחנו מריצים אותו,
ה Action, מורכב מלולאה שרצה כל עוד שהעדיפות מוגדרת ל 8, (הסיבה שאני בודק את המאפיין הזה ולא את המאפיין של PriorityClass, היא בגלל שמסתבר שהמאפיין PriorityClass, כן משתנה כשמנים את העדיפות, אפילו שב taskManager רואים שהוא עדיין על עדיפות normal),
מנסים לשנות את העדיפות, מקבלים מחדש את ה process, מהמערכת, כי אחרת נכנס ללואה אינסופית, בגלל שהמאפיין של BasePriority לא משתנה רק אם מקבלים אותו מחדש, ומחכים 100 מילי שניות, ומנסים שוב.
 
לכאורה הקוד נראה בסדר, אבל בפועל בבדיקות שערכתי על הקוד הזה, זה עבר רק ב חמישים אחוז מהמקרים, בכל הפעמים האחרות, המערכת אמרה לי שהעדיפות היא גבוהה, כשב taskManager זה היה על normal (אני לא בטוח מי משקר, האם זה ה net או ה taskManager)
 
 
בסוף הצעתי להשתמש עם WMI, ומישהו נחמד בשם martin77 כתב את הדוגמא, ותודה לו על כך.
 
 

    1 static void Main(string[] args)

    2 {

    3     Process process = RunProcess(@"C:\mplayerc.exe");

    4     ChangePriorityClass(process);

    5 }

    6 

    7 static Process RunProcess(string proName)

    8 {

    9     Process myProcess = new Process();

   10     myProcess.StartInfo.FileName = proName;

   11     myProcess.Start();

   12 

   13     return myProcess;

   14 }

   15 

   16 static void ChangePriorityClass(Process process)

   17 {

   18     try

   19     {

   20         string queryString = string.Format(

   21             @"SELECT *

   22               FROM Win32_ProcessTrace

   23               WHERE ProcessId = {0}",

   24                         process.Id);

   25 

   26         WqlEventQuery query = new WqlEventQuery(queryString);

   27         ManagementEventWatcher watcher = new ManagementEventWatcher(query);

   28 

   29         Console.WriteLine("Waiting for the event...");

   30 

   31         ManagementBaseObject eventObj = watcher.WaitForNextEvent();

   32 

   33         Console.WriteLine("{0} event occurred.", eventObj["__CLASS"]);

   34 

   35         // Cancel the event subscription

   36         watcher.Stop();

   37 

   38         // Change the priority

   39         process.PriorityClass = ProcessPriorityClass.High;

   40 

   41         return;

   42     }

   43 

   44     catch (ManagementException err)

   45     {

   46         Console.WriteLine(err.ToString());

   47     }

   48 }

 
הקוד הזה עובד במאה אחוז. כי אנחנו ניגשים לבד לתוך הקרביים של מערכת ההפעלה, ומחכים שהוא יגמור לטעון את ה process.
ועכשיו להסברים: לא נכנס כרגע לקרביים של WMI מהסבה הפשוטה, שאני לא מכיר את זה מספיק טוב. (אבל אני חושב ששווה להתחיל לקרוא על זה, ולהכיר אותו יותר לעומק, כמה שאני יודע אפשר לעשות איתו כמעט כל דבר שקשור למערכת ההפעלה ולחומרה).
 
בפונקציית ה main, אנחנו קוראים למתודה שמפעילה את ה process, ומחזירה refernce אליו.
לאחר מכן אנחנו קוראים למתודה שאמורה לשנות את העדיפות שלו,
בשורה  20 עד 24 אנחנו מגדירים שאילתא (בסגנון שמאוד מזכיר את SQL) שמתשאלת את מערכת ההפעלה (חייבים להשתמש ב processId)
בשורה 26 אנחנו יוצרים אובייקט שיודע לתשאל את מערכת ההפעלה.
בשורה 27 אנחנו יוצרים watcher עם ה query
ובשורה 31 אנחנו עוצרים את הריצה של הקוד, עד שנקבל חיווי, שהתרחש event על ה process הנ"ל
בשורה 36 אנחנו מורידים את הרישום של ה watcher
ובסוף אנחנו משנים את העדיפות.
 
וכמו שאמרתי, בכל הבדיקות שעשיתי (ועשיתי הרבה) זה תמיד עבד.
 
ושוב תודה לאותו martin77  אלמוני, שעזר לנו וכתב את דוגמת הקוד.
 
 
עידכון:
יש עוד דרך לבצע את זה, אבל רק בתנאי של process יש user interface, ותודה לדימיטרי שהראה לי את זה.
 

    1 Process RunProcess(string proName)

    2 {

    3     Process myProcess = new Process();

    4     myProcess.StartInfo.FileName = proName;

    5     myProcess.Start();

    6     myProcess.WaitForInputIdle();

    7     myProcess.PriorityClass = ProcessPriorityClass.High;

    8 

    9     return myProcess;

   10 }

שימו לב לשורה 6.

 

Posted: Dec 24 2008, 11:19 AM by Shlomo | with 5 comment(s)
תגים:

Changing the value of the process priority

הייתה לי התכתבות עם מישהו חביב בשם יורם בקשר לשינוי עדיפות של Process,

הבעייה שלו הייתה שהוא ניסה לשנות את העדיפות מתוך הקוד, וזה פשוט לא קרה, ה process נשאר בעדיפות של normal.

הקוד שלו היה כך:

 

    1 void RunProcess(string proName)

    2 {

    3     Process myProcess = new Process();

    4     myProcess.StartInfo.FileName = proName;

    5     myProcess.Start();

    6     myProcess.PriorityClass = ProcessPriorityClass.High;

    7 }

ה Process המדובר היה סוג של Media Player כלשהו,
 
כשבדקתי מה קורה, גיליתי שאם נניח אני מנסה להריץ את notepad, זה עובד כמו שצריך אבל ב Process-ים אחר, בחלקם שה לא עובד,
והסבה לכך, היא, שלוקח ל Process זמן לעלות, ואם אנחנו מנסים לשנות את העדיפות שלו, או כל דבר אחר לפני שהוא לגמרי סיים לעלות, הוא פשוט מתעלם ממה שאנחנו מבקשים ממנו,
ולכן שיניתי את הקוד לזה:
 

    1 void RunProcess(string proName)

    2 {

    3     Process myProcess = new Process();

    4     myProcess.StartInfo.FileName = proName;

    5     myProcess.Start();

    6     Thread.Sleep(1000);

    7     myProcess.PriorityClass = ProcessPriorityClass.High;

    8 }

 
בשורה 6 אנחנו מבקשים מה Thread לנוח לשנייה, ולתת ל Process זמן לעלות,
בצורה הזאת העדיפות באמת משתנה, וכולם מרוצים.
 
 
Posted: Dec 23 2008, 01:24 PM by Shlomo | with 9 comment(s)
תגים:

כשכותבים switch block, האם זה נשאר כך ? הנה התשובה

אז דברנו על זה שהקומפיילר מרגיש חופשי לשחק עם הקוד שלנו איך שנראה לו, ולהפוך בלוקים של switch לבלוקים של if, ואנחנו לא ממש מבינים מה הקומפיילר מנסה לעשות.

אז כשיש כאלו שאלות, למי פונים, כמובן לסשה.

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

 

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

למשל, עבור switch על הרבה string-ים שונים הקומפיילר מייצר Dictionary ומשתמש בו כדי לבדוק לאיזה מקרה אתה מגיע (אתה יכול לבדוק את זה בקלות בעצמך, רק ב- Reflector אל תסתכל על C# אלא על IL).

 

עבור integral types, יש ממש instruction ב- IL שנקרא switch שמממש jump table.

כשיש רק שתי אפשרויות, הקומפיילר בוחר (וכנראה בצדק) להפוך את זה ל- if – זה גם מקצר את ה- IL שנוצר.

 

בסופו של יום, הכל מתקמפל ל- assembly ושם במילא כל הדבר הזה בדרך כלל לא יהיה ממומש באמצעות if-ים במקרה של enum רציף אלא על ידי חישוב של המקום שצריך לקפוץ אליו בהתאם לערך של ה- enum.

אם ה- enum לא רציף (כלומר הערכים לא עוקבים) זה יהפוך לסדרה של if-ים בכל מקרה, או אם יש רק ערך אחד שבאמת צריך לבדוק (כי אז שוב הקוד קצר יותר).

Posted: Dec 21 2008, 10:00 PM by Shlomo | with 2 comment(s)
תגים:,

כשכותבים switch, האם זה נשאר כך ?

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

כי אני ממשיך לכתוב אודותיו.

בכל מקרה, המשכתי קצת לשחק עם הקוד, וגיליתי משהו מעניין, החוק שמחייב אותנו, לממש case עבור כל האפשריות ב enum, עובד רק עם ממשנו יותר מ case אחד, במדה וממשנו רק case אחד, ה Code Analysis יתעלם לגמרי מכל מה שאנחנו כותבים והוא יעביר את הקוד קומפילציה,

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

 

    1     public void f2(MyEnum myEnum)

    2     {

    3         switch (myEnum)

    4         {

    5             case MyEnum.A:

    6                 Console.WriteLine();

    7                 break;

    8             case MyEnum.B:

    9                 Console.WriteLine();

   10                 break;

   11             case MyEnum.C:

   12                 Console.WriteLine();

   13                 break;

   14             default:

   15                 Console.WriteLine();

   16                 break;

   17         }

   18     }

   19 

   20     public void f1(MyEnum myEnum)

   21     {

   22         switch (myEnum)

   23         {

   24             case MyEnum.A:

   25                 Console.WriteLine();

   26                 break;

   27             default:

   28                 Console.WriteLine();

   29                 break;

   30         }

   31     }

   32 }

 
כעת נסתכל מה הקומפיילר באמת עושה, נפתח את ה Refloctor, ונראה מה כתוב שם:
 
 אז הנה הקוד של f2 שבו אנחנו עושים מעבר על יותר מ case אחד:
 
Reflector1
 
 
כמובן בדיוק כמו שאנו מצפים, בלוק של switch שעושה בדיוק מה שכתבנו בקוד,
אבל נציץ על הקוד שמיוצר מ f1, שבו אנחנו עושים case רק על מקרה אחד (ה default לא נחשב)
 
reflactor2
 
אופה, אין שמץ של switch, יש בלוק if רגיל,
מסתבר שמישהו השקיע מחשבה וזמן, כדי לבדוק האם אנחנו עושים case רק על אחד,
לא ברור לי למה, מה היתרון שבלוק if נותן לנו, למה אי אפשר היה להשאיר את זה כ switch,
מה שאני כן יודע, זה שזה דופק לי את ה ForceSwitch, שכתבתי בעמל רב בפוסט הקודם,
 
אשמח אם למישהו יהיה פיתרון.
Posted: Dec 21 2008, 02:50 PM by Shlomo | with 6 comment(s)
תגים:,

איך אפשר לדבג את הקוד של FxCop

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

 אז, בדרך כלל כשאנחנו רוצים לדבג Visual Studio, אנחנו פותחים עוד Visual Studio, ועושים Attach to Process, (תחת תפריט Debug) ובחרים את ה Process שזה בדרך כלל, אותו Visual Studio שאנחנו רוצים לדבג, וברגע שיש Exception, אנחנו מקבלים חיווי ב Visual Studio השני.

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

דבר ראשון בתוך הקוד של ה Code Analysis שאנחנו כותבים, אנחנו צריכים להודיע ל debugger שאנחנו רוצים שכשהוא יגיע לשורה מסוימת, שיעצור שם ושלא ימשיך, נסתכל על הקוד הבא:

 

 

    1     public override ProblemCollection Check(Member member)

    2     {

    3         Debugger.Break();

    4 

    5         Method method = member as Method;

    6         if (method != null)

    7         {

    8             VisitMethod(method);

    9         }

   10 

   11         if (Problems.Count == 0)

   12         {

   13             return base.Check(member);

   14         }

   15 

   16         return Problems;

   17     }

 
שימו לב לשורה 3, אנחנו מודיעים ל debugger בצורה חד משמעית, כשאתה מגיע להריץ את השורה הזאת, תעצור ואל תמשיך,
בשלב שני, נקמפל את הקוד שלנו, ונזרוק את ה dll ל: C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\Rules
(מי שלא זוכר או לא יודע לכתוב חוקים עבור Code Analysis מוזמן לקרוא את הפוסט הקודם)
בשלב שלישי, תחת Tools->Options->Debugging->General, נוריד את הסימון מ Enable Just Ny Code.
 
DebugOptions
 
בשלב רביעי, תחת Debug->Exceptions, נסמן את Common Language Runtime Exceptions ב Thrown
 
Thrown
 
בשלב חמישי נפתח Visual Studio שני, שבו נמצא הקוד שאנחנו מריצים עליו את ה Code Analysis, ונריץ את Code Analisys,
(בשלב הזה אסור לעשות Attach ל Visual Studio שבו נמצא ה Code Analysis)
כשה Debugger יגיע להוראה שאומרת לו לעצור, אנחנו נקבל את המסך הבא:
FxCopDebug
 
 
במדה ונלחץ על Debug, נקבל את המסך הבא:
 
FxCopDebug2
 
 
אנחנו כמובן נבחר ב Instance של הקוד שלנו (זה שמסומן)
 
בדרך כלל נקבל את ההודעה הבאה:
 
NoSource
 
 
נוסיף BreakPoint לשורה, שאנחנו רוצים לעצור שם ונלחץ על F5, ואז נוכל לדבג.
 
תהנו.
ותודה לאלכס אבוגוב על העזרה.
 
RealDebug

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.

 

 

Convert function in DataTable.Select

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

לדוגמא, אם הטבלה שלנו מכילה פרטים אודות אנשים, נוכל לכתוב את השורה הבאה.

 

    1     DataRow[] rows = table.Select("Id > 10");

ונקבל מערך של שורות שעמודת ה Id גדולה מ 10,
דרך אגב בדרך כלל עדיף לכתוב את הקוד הבא
 

    2     string filter = "Id > 10";

    3     DataView view =

    4         new DataView(table, filter, "",

    5                     DataViewRowState.CurrentRows);

 
כי לדוגמא אובייקטים שמקבלים DataSource יודעים יותר טוב לעבוד עם DataView מאשר עם מערך של DataRow.
 
עכשיו, נניח שיש לנו עמודה מסוג Guid, ואנחנו רוצים להביא את כל האנשים מתוך רשימת Guids שבחרנו, לכאורה הקוד יראה כך.
 

    6     List<Guid> allSelectedGuid = GetSelectedGuid();

    7     string allGuid = "";

    8     foreach (Guid guid in allSelectedGuid)

    9     {

   10         allGuid = string.Concat(allGuid,

   11                                 "'",

   12                                 guid.ToString(),

   13                                 "'",

   14                                 ", ");

   15     }

   16     allGuid = allGuid.Remove(allGuid.Length - 2, 2);

   17     string filter = string.Format("Identity IN ({0})", allGuid);

 
הסבר קצר:
שורה 6 מחזירה רשימה עם כל ה Guid שהמשתמש בחר.
שורה 8 עד 15, אנחנו רצים על ה Guid בלולאה כדי לייצר את השאילתא.
שורה 16 אנחנו מורדים את שני התווים האחרונים של השאילתא, (כי יש שם פסיק ורווח מיותרים).
ובסוף אנחנו מייצירים את הפילטר שנראה כך:
 

   18     Identity IN (

   19                 'b93a95f2-4f84-4d36-80de-bd74ac7725c8',

   20                 '14dee73e-0631-488c-8f5f-ad806c1fd2ac'

   21                 )

 
השאילתא הזאת היא תקינה ב SqlServer ותחזיר את מה שאנחנו רוצים,
אבל אם ננסה על ה DataTable לקבל DataView או מערך של DataRow על בסיס הפילטר הזה, אנחנו נקבל את השגיאה הבאה:
 
SelectTablebug
 
והסבה היא די פשוטה, אם ה Type של העמודה הוא מסוג Guid, אנחנו לא יכולים להשוות עם מחרוזות.
 
ולכן אנחנו צריכים לכתוב את הפילטר הבא.

   22     string filter = string.Format(

   23             "CONVERT(Identity, 'System.String') IN ({0})",

   24             allGuid);

 
בצורה הזאת הפילטר יעבוד, ונוכל לקבל את ה DataView שאנחנו רוצים.
 
כאן תוכלו לקרוא עוד על הפונקציות שאפשר להשתמש ב Select על DataTable.
Posted: Dec 16 2008, 08:46 AM by Shlomo | with 1 comment(s)
תגים:

DevAcademy3 רשמים אישיים

היי,

אני אנסה לסכם איפה שהייתי ומה שהיה,

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

אני הכרתי הרבה אנשים, לא את כולם אני זוכר כרגע, ויסלחו לי אלה שהכרנו ושכחתי לרשום,

אבי פינטו, רותם (תודה על כל התגובות), שחר, עדלי משיח והיה ממש נחמד לדבר שיחה עמוקה על Reporting Services עם אחותו אלה

וגם היה מאוד כיף להכיר את האיש והאגדה גיא בורשטיין (לא שכחתי שהבטחת לי טיפים)

 

ונעבור להרצאות.

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

בהרצאה השנייה הייתי אצל אייל ורדי בנושא של http web services, התוכן היה עמוק ודרש היכרות מוקדמת עם הטכנולוגיות, אבל יצאתי עם חומר חדש.

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

 ארוחת הצהריים הייתה טובה, וכבר כתבתי שאני לא משגיח הכשרות

בהרצאה הרבעית הייתי אצל גל קוג'מן בנושא Internet explorer 8, היה כיף, צורת ההגשה של החומר, ההומור, ואפילו ההתחמקות מהקריסה של הדמו, יצאתי מרוצה.

בהרצאה החמישית הייתי אצל שמעון דהן ב Lab על Entity Framework, דווקא היה נחמד, מעבר לעובדה שהעבודה עם העכבר הייתה הזוייה, הוא פשוט לא תפקד, הייתי צריך להוציא את המיטב שבי כדי להזכר בכל קיצורי המקלדת של Visual Studio, וכמובן שה Lab לא נותן הרבה ידע עקב היותו מאוד פשוט וברמה הכי בסיסית שיכולה להיות.

וכמובן ארוחת הערב עם המרצים והבלוגרים הייתה נהדרת.

 

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

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

 

אני לא משגיח הכשרות

חבר'ה, אני מפתח תוכנה אני לא משגיח הכשרות, בערך עשרים איש שאלו אותי האם זה כשר,

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

עד עכשיו היה נהדר, נקווה שגם בהמשך היום יהיה כך,

הבאג המוזר (קידום ערכי משתנים בכל צפייה)

יצא לי לאחרונה להתקל בהתנהגות מוזרה.
נראה את קטע הקוד הבא:

    1 public class Person

    2 {

    3     private static int m_Counter;

    4 

    5     public static int Counter

    6     {

    7         get

    8         {

    9             m_Counter++;

   10             return m_Counter;

   11         }

   12     }

   13 }

 

לכאורה כל פעם שנגש למאפיין נקבל index רץ.

אבל בואו נראה איך הכל משתבש על ידי ה debugger.

בתמונה אנחנו רואים, שכשאנחנו מסתכלים על הערך של המאפיין הוא שווה לאחד, עכשיו נעבור לתמונה הבאה

PersonCounter1

 

PersonCounter2

 

מה אנחנו רואים ?

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

למעשה אני לא מכיר פתרון אמיתי לבעייה, מה שאפשר לעשות זה:

  1. להפוך את המאפיין למתודה, ובצורה הזאת כשנסתכל על האובייקט זה לא ישנה את הערך,
  2. להשתמש ב attribute של DebuggerBrowsable בצורה הזאת

    1     [DebuggerBrowsable(DebuggerBrowsableState.Never)]

    2     public static int Counter

    3     {

    4         get

    5         {

    6             m_Counter++;

    7             return m_Counter;

    8         }

    9     }

זה יגרום לכך שלא יראו את המאפיין ב debugger, ולכן זה לא יתקדם רק דרך קריאה מהקוד.
Posted: Dec 13 2008, 01:57 PM by Shlomo | with 7 comment(s)
תגים:,

מוטב מאוחר מאשר לעולם לא

שלום לכולם.

רציתי לשתף אתכם במה שאני מרגיש.

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

אז אני רוצה להודות לכל הקוראים והכותבים וכמובן לכל המגיבים.

ותודה מיוחדת מגיעה כמובן לגיא בורשטיין.

אז תודה לכולכם, ונפגש ב Developer Academy

Posted: Dec 11 2008, 02:31 AM by Shlomo | with 4 comment(s)
תגים:
More Posts Next page »