מחלקות גנריות
ה - Generics זו קבוצת מחלקות חדשה שמכילה מספר אוספים המשמשים לאסוף סוג מסוים של נתונים. בואו ניקח לדוגמא את ה ArrayList שכולנו מכירים. אנו יכולים להוסיף אליו נתונים על ידי Add, ולא משנה איזה סוג של נתון, הכל נאסף בפנים, ומה קורה כשאני רוצה למשוך את הנתונים? אני צריך להגיד מה סוג הנתון שהכנסתי לתוכו. אם הכנסתי מספר מסוג int אז כשאני מושך את המספר אני צריך לעשות casting:
int j=(int)myArray[0];
יש 2 בעיות בפעולה הזאת:
א. אולי מה שיש בתוך המערך הוא לא int אלא משהו אחר ואני טועה...? הקומפיילר לא ידע לתקן אותי ורק כשהאפליקציה תתרסק אני אבין את זה...
ב. כל פעם שלוקחים סוג מידע מסוג ערכי (כמו int, bool, float וכו', להבדיל מממחלקות שאנו פונים אליהם דרך מצביע) ומכניסים אותו למערך של אוסף , יש צורך להפוך אותו לאובייקט (boxing) וכשאנו מושכים אותו בחזרה להחזיר אותו מאובייקט לסוג ערכי (unboxing), כל הפעולות האלו גוזלות משאבים מהמחשב.
אז את 2 הבעיות האלה אמור ה Generics לפתור (לגבי ביצועים הדבר נתון במחלוקת...)
בעזרת ה Generics אני יכול להגדיר אוסף, אבל לציין איזה סוג משתנים הוא יכיל, וכך הקומפיילר לא יתן לי לטעות בסוג המשתנה
בואו ניקח לדוגמא את המחלקה Queue שמופיעה גם בתור אוסף רגיל וגם בתור Generics. ליצירת Queue רגיל היינו כותבים:
System.Collections.
Queue queue=new System.Collections.Queue();
ואילו ליצירת Queue מסוג Generics נכתוב:
System.Collections.Generic.
Queue<int> qGeneric = new System.Collections.Generic.Queue<int>();
במקרה הזה מדובר על Queue שיכיל משתנים מסוג int.
עכשיו אני אוכל להכניס לשם רק int וכשאמשוך את הנתונים לא אצטרך לבצע casting, אלא ישר אקבל אותם בתור int.
int
j = qGeneric.Dequeue();
רק בשביל התכונה הזאת, שמונעת טעויות, כבר כדאי להשתמש ב Generics ככל האפשר. לגבי היתרון השני, ביצועים, אז פה זה כבר לא תמיד ברור. בבדיקות שעשיתי התוצאות לא היו חד משמעיות. לגבי הדוגמה הספציפית שלנו דווקא ה Generics ניצחו באיזה 6 אחוז. בבדיקות אחרות עם string התוצאות היו אחרות... נראה שההפרש בביצועים הוא שולי ועדיף להשתמש ב Generics
מי שירצה לחזור על הבדיקות:
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 100000; i++)
{
queue.Enqueue(i);
int j = (int)queue.Dequeue();
}
long time2 = watch.ElapsedMilliseconds;
lblNormal.Text = time2.ToString();
watch.Reset();
watch.Start();
for (int i = 0; i < 100000; i++)
{
qGeneric.Enqueue(i);
int j = qGeneric.Dequeue();
}
long time = watch.ElapsedMilliseconds;
lblGenerics.Text = time.ToString();
להורדת הפרוייקט