DCSIMG
C#,.Net Internals - Liran Chen's Blog

Liran Chen's Blog

.Net Internals, Debugging, Multithreading - and More!

Browse by Tags

All Tags » C# » .Net Internals (RSS)
String.Format Isn't Suitable for Intensive Logging
אחד השיעורים הראשונים שכל מפתח דוט-נט לומד לשנן, הוא ש"בכל מקרה בו רוצים לחבר הרבה מחרוזות אחת לשניה, אסור בתכלית האיסור להשתמש באופרטור +, ובמקום זה להשתמש במחלקה StringBuilder". אז אחרי הדקלום המושלם הזה, אתה שואל "אוקיי, אבל למה בעצם?", והתשובה היא בדרך כלל "בגלל שמחרוזות הן Immutable, זה אומר ששימוש באופרטור+ יביא להקצאות מיותרות של מחרוזות שיהווה כל מיני 'שלבי ביניים' עד שנגיע למחרוזת הסופית". כפי שאני רואה את זה, הדקלום הזה יותר מטעה מאשר מה שהוא תורם....
Mysteries with Circular Dependencies
אם יש משהו אחד בסיסי שכולם יודעים על פיתוח תוכנה, הוא שלא ניתן ליצור תלות מעגלית בין פרוייקטים (DLL'ים). אם למשל יש לנו פרוייקט A, שפונה לפרוייקט B, אז לא יהיה ניתן שאותו פרוייקט B יפנה בחזרה לפרוייקט A בתור רפרנס. אם היינו עושים דבר כזה, היתה נוצרת לנו תלות מעגלית בין שני הפרוייקטים. וזה רע, בגלל שכשהקומפיילר ירצה לקמפל את A, הוא יראה שהוא תלוי ב-B, אז הוא יגש ל-B וינסה לקמפל אותו. אבל אז הוא יגלה ש-B למעשה תלוי ב-A, ואז הוא יחזור חלילה עד אין קץ.. האמנם? אם יצא לכם לפשפש מספיק במבנה הספריות...
DateTime.Now Causes Boxing
אולי לא הייתם מיודעים לכך, אבל בכל פעם שאתם פונים ל-DateTime.Now, אתם גורמים בעקיפין הקצאת זכרון דינאמית על ידי Boxing של Int32. הסיבה לכך טמונה עמוק בתוך המימוש של Now, שאם נסתכל מקרוב, נוכל לראות שהוא למעשה עוטף קריאה ל-UtcNow והמרתו לזמן מקומי על ידי קריאה לפונקציה ToLocalTime. עם הקריאה ל-UtcNow אין בעיה, מאחר ובסך הכל נעשית קריאה פנימית ל- GetSystemTimeAsFileTime , שמחזיר את הזמן הנוכחי בפורמט UTC. הבעיה האמיתית טמונה במימוש של ToLocalTime, או למעשה במחלקה CurrentSystemTimeZone בה היא נעזרת...
Understanding SyncBlocks
בדוט-נט קיים מנגנון סנכרון אובייקטים מובנה. ובין אם אנחנו מודעים לזה או לא, אנחנו משתמשים בו בכל פעם שאנחנו באים לסנכרן קטעי קוד באפליקציה שלנו. המשמעות היא שאנחנו לא צריכים לגשת לאובייקטי סנכרון מובנים של מערכת ההפעלה, בכל פעם שאנחנו רוצים לעשות lock קטן בקוד. מה שמקנה לנו יתרון בביצועים בהשוואה לשימוש באובייקטי סנכרון כגון Mutex או Semaphore (במקרה שלנו, אובייקט הקרנל היחיד בו משתמשים הוא Event). עבור כל אובייקט שקיים אצלנו באפליקציה, קיים גם SyncBlock שמשוייך אליו. אותו אובייקט SyncBlock אחראי...
Objects Structure: Under The Hood
אובייקטים בדוט-נט אינם בנויים בתור יחידות בודדת ושלמות שנמצאות על ה-GC Heap, שמכילות את ה-Data Member'ים שהגדרנו להן. בפועל, מעבר למידע "הנראה לעין" שאנחנו מגדירים כשאנחנו כותבים מחלקה חדשה, מתווספים גם מספר שדות "בלתי נראים" לאובייקט שלנו שנמצאים באזורים שונים בזכרון. השדה הראשון והבסיסי הוא המצביע ל-MethodTable השייך לטיפוס שלנו. אני מדלג על ההסבר על ה-MethodTable והמידע שהיא מכילה (שימו לב שלא מדובר ב-VTable עצמו, אלא בטיפוס שבין היתר מכיל מצביע אליה), ובמקום זה אתמקד בנקודה...
Events Thread Safety Hazards
דבר אחד שימושי בדוט-נט הוא התמיכה הטבעית הקיימת ל-Event'ים. כדי ליצור אירוע למחלקה שלנו, כל מה שעלינו לעשות הוא להגדיר Event חדש בעזרת ה-Delegate המתאים, וזהו זה. שימו לב שאפילו לא היינו צריכים לכתוב Accessors כלשהם, מאחר וכברירת מחדל, אלא אם כן לא הגדרנו אחרת, הקומפיילר יחולל כבר Accessor'ים משלו שידאגו לנהל עבורנו את הרישומים עבור האירוע שהגדרנו. זוהי נקודה שהרבה פעמים לוקחים כמובן מאליו, ולא מפנים אליה תשומת לב מיוחדת, ולמרות זאת, מסתתרת מאחוריה משמעות קריטית כש-Multithreading נכנס לתמונה...
Object.ReferenceEquals vs. The Equality Operator
לפני כמה פוסטים הבנו מה המשמעות של אופרטור ההשוואה (==) כשנעשה בו שימוש בקונטקסט של Reference Types. למעשה הגענו למסקנה שבמימוש הבסיס הוא למעשה עונה לנו על השאלה "האם 2 הרפרנסים שיש לי מצביעים לאותו אובייקט?", כלומר יש לנו כאן השוואה של כתובות בזכרון. אם הן זהות, קיבלנו true; אחרת, false. אבל רק רגע, בנקודה הזאת אנחנו נזכרים לרגע בפונקציה ReferenceEquals שנמצאת תחת מחלקת הבסיס Object. כמו שמשתמע מהשם, גם התפקיד שלה הוא לענות בדיוק על אותה השאלה. אז אם 2 הדרכים הללו למעשה "עושות אותו...
Arithmetic Overflow Checking
שאלה: האם לתוכניות שרצות בדוט-נט יש בדיקה אוטומטית עבור Arithmetic Overflows? קחו לדוגמה את התוכנית הבאה, מה לדעתכם יהיה הפלט? או שבכלל תזרק שגיאה? class Program { static void Main( string [] args) { int foo = 1; int bar = int .MaxValue + foo; Console .WriteLine(foo); } } אם הניחוש שלכם היה 2147483648- (שווה ערך ל int.MinValue), צדקתם. זאת טעות נפוצה לחשוב שכברירת מחדל הסביבה תבדוק כל הזמן האם קיימת אי התאמה בין גודל הערך שאותו אנחנו מנסים להכניס למשתנה. רוב המפתחים מצפים שעל פעולה כמו בדוגמה למעלה...