מדריך #C מתקדם – Generics
לעיתים נרצה לבנות מחלקות אשר מאד דומות בתבניתם, ושונות רק בסוג הנתונים שהם מחזיקות.
דוגמאות:
- נרצה מחלקה Point המייצגת נקודה במישור בעלות יכולות, כמו למשל להזיז את הנקודה, כאשר לעיתים נרצה שהאורדינאטות (x,y) של הנקודה יהיו מסוג int ולעיתים נרצה שיהיו מסוג double (או מכל סוג אחר – long, byte, decimal…)
- מחלקה לניהול רשימה של נתונים (Collection) עם יכולת להוסיף ולמחוק איברים כאשר בכל פעם נרצה לשים שם נתונים אחרים
בעזרת הידע שיש לנו עד עתה נצטרך לבנות את המחלקות מספר פעמים, פעם אחת עבור כל טיפוס. אפשרות אחרת היא להשתמש בטיפוס object אך אפשרות זו לא מספיק טובה כי היא מחייבת אותנו לבצע casting בכל פעם שנרצה לעבוד עם המשתנה ובנוסף אנו עלולים לטעות ולהכניס למשתנה משתנה מטיפוס שלא התכוונו אליו והקומפיילר לא יתריע על כך, אלא נקבל את השגיאה רק בזמן ריצה ב- casting הלא חוקי.
Generics נותן פתרון לבעיה זו בכך שהוא מאפשר להגדיר גם את סוג המשתנה כפרמטר, כך שנוכל ביצירת האובייקט לקבוע מה יהיה הטיפוס עבור האובייקט המסוים ובאובייקט אחר נקבע טיפוס אחר. בשיטה זו לא נצטרך לבצע casting מפני שאנו מגדירים את הטיפוס ואם ננסה להכניס ערך מטיפוס לא נכון בטעות נקבל שגיאת קומפילציה.
בכדי להשתמש ב- Generics יש להגדיר את הטיפוס כפרמטר באמצעות סוגריים משולשים <> מיד לאחר שם המחלקה לדוגמא:
class Point <T>
{
...
}
לאחר מכן נוכל להשתמש בפרמטר זה בתוך המחלקה:
class Point<T>
{
private T x;
private T y;
public T X
{
get { return x; }
set { x = value; }
}
public T Y
{
get { return y; }
set { y = value; }
}
public Point(T x, T y)
{
X = x;
Y = y;
}
public override string ToString()
{
return string.Format("X = {0}, Y = {1}", X, Y);
}
}
כאשר ניצור את האובייקט נספק לו את הפרמטר של הטיפוס גם כן בסוגריים משולשים. לדוגמא Point כאשר ה- T הוא מסוג int:
Point<int> pInt = new Point<int>(10, 5);
שימו לב שבדוגמא הבאה שתי השורות האחרונות יגררו שגיאת קומפילציה מפני שטיפוס הנתונים מוגדר מראש ולא ניתן להכניס ערך מסוג אחר:
static void Main(string[] args)
{
Point<int> pInt = new Point<int>(10, 5);
Point<string> pString = new Point<string>("a", "b");
pInt.X = "a";
pString.X = 10;
}
עוד נקודות חשובות לגבי Generics:
- ניתן לקבל יותר מפרמטר אחד עבור מספר סוגים של משתנים.
- ניתן לבנות כמעט כל אלמנט שאנו מכירים כ- generics כגון: class, struct, method, delegate, interface
- ניתן לרשת מחלקה generics ולהגדיר לה את הטיפוסים כקבועים
דוגמא להורשת מחלקה generics:
class PointDouble : Point<double>
{
}
בספריות של NET. ישנם הרבה טיפוסים מוכנים המממשים את הרעיון של Generics וזמינים לשימושינו, לדוגמא:
- <IComparable<T – למימוש IComparable עם הפרמטר המתאים לפונקציה CompareTo
- <List<T – דומה ל ArrayList אך עם הגדרת הטיפוס של הנתונים ביצירת האובייקט
- <Dictionary<TKey, TValue – דומה ל- Hashtable עם הגדרת הסוג של ה- key ושל ה- value ביצירת האובייקט
תגובות בפייסבוק