פירוש המילה where
-
קיבלתי תרגיל לכתוב עץ בינרי גנרי שיממש את המימשק IComparable<T
אלא שלא התבקשתי לממש את המתודה CompareTo אלא רק להשתמש בה באחת המתודות שכתבתי (שמוסיפה ערכים חדשים לעץ הבינרי).
כשניסיתי להדר את המחלקה קיבלתי הודעת שגיאה שאם הבנתי אותה נכון היא אמרה שלא מימשתי את המימשק במחלקה (Interface בלעז..), ומה שנכון - נכון :?
אך לא הבנתי מדוע בספר הם לא מבקשים ממני לממש את המתודה הנ"ל, עד שמצאתי שבדוגמ' שלהם הם משתמשים בקוד הנ"ל:public class Tree<T> where T :IComparable<T>
הוספתי גם אני את המילה where T לקוד, ובא לציון גואל!! :lol:
מישהו יכול להסביר לי מה פירושה? האם הכוונה לציין שמספיק לקרוא למתודה הנ"ל במחלקה גם בלי להגדיר אותה מחדש? לעומת המצב בו אינני כותב את המילה הזאת??
תודה רבה מראש!!פורסם במקור בפורום CODE613 ב15/06/2015 21:38 (+03:00)
-
פירוש המילה where זה "כאשר" הרחבה:
במחלקה גנרית אפשר ליצור מופע ממנה ע"י כל סוג נתון ע"י נתינתו כפרמטר בסוגריים הזויתיות בעת יצירת מופע.
בכתיבת המחלקה, כיון שאתה עוד "לא יודע" מה הסוג, אתה מתייחס אליו ע"י המשתנה ששמת בסוגריים הזויתיות בהצהרת הקלאס, במקרה שלך T.
בשביל לצמצם את מרחב הסוגים האפשרי ליצירה ע"י המחלקה, וכדי שתוכל להניח על אופיו של הסוג הנתון, אפשר לתת "אילוץ" שרק סוגים שעונים על הגדרות מסויימות יהיו זמינים ליצירת המחלקה על ידם.האילוץ נעשה ע"י כתיבת where. באילוץ אפשר לתת את ההגבלות:
class - הסוג יכול להיות רק מחלקה. א"א אח"כ ליצור Three<int>.
struct - הסוג יכול להיות רק מבנה, כדגומת int.
new() - לסוג חייב להיות קונסטרקטור נגיש.
שם סוג כלשהוא: הסוג חייב לרשת/לממש מהסוג שצויין.אחרי שמחילים הגבלה על הסוגים בהצהרת מחלקה גנרית, אפשר להשתמש בהגבלה הזו כ"הכרות" עם הטיפוס.
למשל במקרה שלך, ציון הIComparable מאפשר לך לגשת למתודה CompareTo של הT בתוך קוד המחלקה הגנרית וזאת אף על שסוגו עדיין "פתוח" ולא ידוע.אני לא יודע למה הVS דרש שThree יממש IComparable כנראה ביצעת פעולת מיון וכדומה באופן עקיף או ישיר.
מקור בMSDN: https://msdn.microsoft.com/en-us/library/d5x73970.aspx
פורסם במקור בפורום CODE613 ב15/06/2015 22:26 (+03:00)
-
[קודם כל תודה רבה רבה!! אין כמוך!!
השתמשתי במתודה CompareTo במתודה הנ"ל:public void Insert(T newItem)//הוספת ערכים לעץ הבינארי { T currentNodeValue = this.NodeData; if(currentNodeValue.CompareTo(newItem)>0) {//אם הערך החדש גדול מהקיים הוא מכניס אותו לענף השמאלי if(this.LeftTree==null) { this.LeftTree = new Tree<T>(newItem); } else { this.LeftTree.Insert(newItem); } } else//אם הערך קטן או שווה לקיים הוא מכניס אותו לענף הימני { if(this.RightTree==null) { this.RightTree = new Tree<T>(newItem); } else { this.RightTree.Insert(newItem); } } }
זו הודעת השגיאה שהוא הציג לי כשלא השתמשתי בwhere:
פורסם במקור בפורום CODE613 ב15/06/2015 22:33 (+03:00)
-
אז ברור למה הוא עושה בעיות, אתה קורא לcurrentNodeValue.CompareTo, ומנין לך שיש לעצם הגנרי שלך כזו מתודה?
אחרי האילוץ זה נהפך ל"ידוע" עבורך שהעצם הגנרי מסוג כלשהוא הוא בודאי מממש את המתודה, וגם הIDE מכיר בזה ומפסיק "לנבוח"פורסם במקור בפורום CODE613 ב15/06/2015 23:05 (+03:00)
-
תודה רבה דוד!! החכמתנו!!
מה הייתי עושה בלעדיך???עכשיו שאלה נוספת בקשר למחלקה הנ"ל.
אני כותב את הקוד הבא:Tree<int> tree1 = new Tree<int>(10); tree1.Insert(5); tree1.Insert(11); tree1.Insert(5); tree1.Insert(-12); tree1.Insert(15); tree1.Insert(0); tree1.Insert(14); tree1.Insert(-8); tree1.Insert(10); tree1.Insert(8); tree1.Insert(8); tree1.WalkTree();
אבל במקום שהוא ידפיס לי על המסך את רשימת הערכים הללו ע"י המתודה WalkTree
הוא מדפיס לי רשימה של אפסים כמניין הערכים.. אולי הייתי צריך לדרוס את המתודה ToString ולהגדיר אותה בעצמי?? (אם כן, אשמח לעזרה כיצד לעשות זאת כי כשאני מנסה הוא כותב לי שהוא לא יודע להמיר ערך T לstring.. אם הוא לא יודע - אז איך אני אדע?? :lol: )
הנה הקוד של המתודה WalkTree:public void WalkTree() { if(this.LeftTree!=null) { this.LeftTree.WalkTree(); } Console.WriteLine(this.NodeData.ToString()); if(this.RightTree!=null) { this.RightTree.WalkTree(); } }
פורסם במקור בפורום CODE613 ב15/06/2015 23:19 (+03:00)
-
הסתדרתי...
עבדתי עם Debugging והצלחתי לעלות על הטעות שלי..
כתבתי משתנה פרטי ואח"כ properties והשתמשתי במאפיינים אוטו' כלומר get ו set בלי הגדרה.
משום מה, שמתי לב שכאשר הוא קלט את הערכים שלי הוא שמר אותם רק במשתנה הפרטי ואילו המאפיינים נשארו null, ובמתודה של ההדפסה היא ציינה לו להדפיס את הערך של המאפיינים כך שהוא לא הצליח להדפיס כלום. (אח"כ כשניסיתי ליצור עץ חדש של סטרינג הוא קרס.. כי הוא לא ידע מה הסטרינג של null...)
אז שיניתי את ההגדרות כך:private T nodeData; private Tree<T> left; private Tree<T> right; //properties public T NodeData { get { return this.nodeData; } set { this.nodeData = value; } } public Tree<T> LeftTree { get { return this.left; } set { this.left = value; } } public Tree<T> RightTree { get { return this.right; } set { this.right = value; } }
והכל בא על מקומו בשלום
אלא שאני לא מבין כי למדתי שא"צ לכתוב את הנ"ל והוא יודע לזהות מאפיינים אוט' אז מה קרה הפעם? מדוע הוא חשב שהמאפיינים והמשתנה עצמו הם שונים ולא מפנים לאותו ערך?? :?פורסם במקור בפורום CODE613 ב15/06/2015 23:50 (+03:00)
-
מאפיינים אוטומטיים עובדים. הבעיה שגם יצרת פרטיים משלך, וציפית שהקומפיילר יאחסן את הערך במשתנה שאתה יצרת כprivate, בעוד למעשה הוא בונה תמיד אחד משלו. אם אתה עושה מאפיין אוטומטי אז אתה פונה רק אליו. לא למשתנה פרטי כלשהו.
סוף טוב בכל אופן.
פורסם במקור בפורום CODE613 ב16/06/2015 11:54 (+03:00)
-
אז למסקנה: אם אני משתמש במאפיינים אין צורך להשתמש במשתנה פרטי לאותו דבר
נכון, ליתר בהירות: מאפיין זה סה"כ שילוב של פונקציות בשם set וget. פונקציה הרי לא זוכרת כלום אז הקריאה והכתיבה נשענים על מקור כל שהוא, בדרך כלל משתנה פרטי. במאפיין אוטומטי המהדר מקצה משתנה פרטי (שהינו בלתי נגיש למתכנת) וגם מרחיב את פונקציות הset והget לקריאה וכתיבה למשתנה הזה.
פורסם במקור בפורום CODE613 ב16/06/2015 21:42 (+03:00)