C# 4.0 Part 1 (First glance on the dynamic)
אני לומד את C# 4.0 יותר לעומק (עבור הרצאה שאני מתכוון להעביר), ואני מתכוון לכתוב סדרת פוסטים שיכנסו יותר לעומק של התכונות החדשות של השפה.
אחד מהחידושים הגדולים של השפה (שיספק לי חומר לכמות פוסטים נכבדה) הוא ה - DLR (Dynamic Language Runtime
אנחנו נחקור מה הוא עושה מאחורי הקלעים בפוסטים הבאים, כרגע נראה מה הוא נותן לנו לעשות (איך הוא עושה את זה, נדבר בהזדמנות אחרת)
dynamic age = 23;
dynamic name = "Shlomo";
dynamic children = new List<string>() { "yossi", "meir", "rivka" };
Console.WriteLine(++age);
children.Add("shara");
foreach (var item in children)
{
Console.WriteLine(item);
}
כמו שאנחנו רואים, יש לנו מילת מפתח חדשה בשם "dynamic" שיכולה לקבל כל דבר.
זה לא var, ההבדל המהותי ביניהם ש - var מקבל את ה - type האמיתי שלו בזמן קומפילציה, לעומת זאת dynamic מקבלת לכאורה את ה - type האמיתי בזמן ריצה (למה לכאורה, נדבר בפוסט אחר).
אפשר להכניס כל type ל - dynamic, ולהפעיל כל מתודה או מאפיין שהיינו יכולים להפעיל על הטיפוס האמיתי, אבל אין לנו intelicence, הבדיקה האם באמת המאפיין או המתודה קיימים לאותו אובייקט, יתבצעו בזמן ריצה.
השאלה המתבקשת מה זה נותן לנו, לפניכם דוגמא אחת:
נניח שאנחנו רוצים לכתוב מתודה שיודעת לקבל מספרים מסוג int ולהחזיר את סכומם, מן הסתם נכתוב קוד כזה:
public static int Sum(params int[] values)
{
int sum = 0;
for (int i = 0; i < values.Length; i++)
{
sum += values[i];
}
return sum;
}
מה יקרה עם נרצה double, נצטרך לכתוב את המתודה הבאה:
public static double Sum(params double[] values)
{
double sum = 0;
for (int i = 0; i < values.Length; i++)
{
sum += values[i];
}
return sum;
}
אבל מה יקרה עם נרצה לכתוב מתודה שיודעת לקבל כל סוג שמממש את האופרטור += (כמו DateTime) האם נצטרך לכתוב מתודה עבור כל סוג ?
(אי אפשר עם Generic כי אין לנו constrain על אופרטור =+)
עם dynamic לא נצטרך:
public static dynamic Sum(params dynamic[] values)
{
dynamic sum = values[0];
for (int i = 1; i < values.Length; i++)
{
sum += values[i];
}
return sum;
}
לא משנה איזה טיפוס נשלח לפונקציה, כל עוד שהוא יודע לעשות =+, הפונקציה תעבוד, לדוגמא
Sum(2, 3, 4);
Sum("a", "b", "c“);
Sum(DateTime.Now, new TimeSpan(3, 3, 3));
יחזיר (בהתאמה)
9
abc
15/06/2009 00:27:43
בואו נראה עוד דוגמא שימושית ל - dynamic:
כשאני מלמד interface, אחד הדוגמאות השימושיות הוא - למיין כל סוג של מערך באמצעות IComparable.
נניח שיש לי מערך של int ואני רוצה למיין אותו, מן הסתם יהיה לי קוד כזה:
public static void Sort(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length - 1; j++)
{
if (array[j] > array[j + 1])
{
int tmp = array[j];
array[j] = array[j + 1];
array[j + 1] = tmp;
}
}
}
}
מה יקרה עם יש לי מערך של person, שזה מציב לפנינו שני בעיות, הראשונה שהפונקציה מקבלת מערך של int והשנייה לפי מה נעשה את ההשוואה האם צריך להחליף את המיקום של האובייקטים במערך.
את הבעייה הראשונה אפשר לפתור באופן פשוט הפונקציה תקבל אובייקט מסוג Array (האבא של כל המערכים),
את הבעייה השנייה נפתור באמצעות IComparable, והקוד שלנו יראה כך:
public static void Sort(Array array)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length - 1; j++)
{
IComparable comparable = (IComparable)array.GetValue(j);
if (comparable.CompareTo(array.GetValue(j + 1)) == 1)
{
object tmp = array.GetValue(j);
array.SetValue(array.GetValue(j + 1), j);
array.SetValue(tmp, j + 1);
}
}
}
}
זוהי דוגמא נהדרת להסבר על interface, מה שמעצבן של - Array אין מימוש של indexer, (למעשה יש, אבל הוא מוגדר כ - internal) מה שגורם לקוד להיראות מגעיל עם כל ה - GetValue וה - SetValue.
בואו נעביר את הקוד ל - dynamic
public static void Sort(Array array)
{
dynamic dynamicArray = array;
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length - 1; j++)
{
if (dynamicArray[j].CompareTo(dynamicArray[j + 1]) == 1)
{
dynamic tmp = dynamicArray[j];
dynamicArray[j] = dynamicArray[j + 1];
dynamicArray[j + 1] = tmp;
}
}
}
}
הופה, תראו איזה קוד נקי יצא לנו, אנחנו מקבלים Array, בתוך הפונקציה אנחנו מסתכלים על זה באמצעות dynamic, ואנחנו יכולים לגשת ל - indexer, וכמובן לגשת למתודת ה - CompareTo מבלי צורך בהמרה ל - IComparable.
בפוסט הבא אני אדגים איך אפשר לכתוב מימוש של מחשבון באובייקט דוט נטי, ומימוש של מחשבון ב - Javascript, נבנה WinForm שיקבל אחד משני המימושים (או את האובייקט הדוט נטי או את אובייקט ה - Javascript עטוף באובייקט Com) ויוכל להפעיל את הפונקציות ללא צורך ב - Reflection.