מדריך LINQ – לפני LINQ
var keyword
אפשר להשתמש ב – var במקום לכתוב את ה – type המלא, זה יכול לחסוך כתיבה לדוגמא:
var list = new List();
אין צורך לכתוב בצד שמאל את טיפוס המשתנה היות שכתבנו בצד ימין, חשוב לשים לב שלא מדובר בטיפוס מסוג חדש אלא זה בסך בכול טריק של הקומפיילר שמעתיק את צד ימין לצד שמאל, ולכן אי אפשר לכתוב קוד כזה:
var list = null;
או קוד כזה
static void f(var num)
מכיוון שהקומפיילר לא יודע באיזה טיפוס מדובר.
לכאורה זה נראה כמיותר אבל למעשה צריך את ה – var לשימוש ה – Anonymous Types כפי שנראה בהמשך ובנוסף כשאתם מגדירים טיפוס מורכב (כמו Dictionary עם כל מיני טיפוסים) ה – var יכול לפשט את קריאות הקוד.
Anonymous Types
יש לנו את היכולת לייצר בזמן כתיבת הקוד טיפוסים חדשים מבלי להגדיר אותם במפורש, לדוגמא:
var pi = new { Name = "Shlomo", Age = 25 }; Console.WriteLine("Name: {0}, Age: {1}", pi.Name, pi.Age);
למעשה מאחורי הקלעים מוגדר בזמן קומפילציה מחלקה חדשה עם שני המאפיינים שהוגדרו (הם לקריאה בלבד).
למעשה הסיבה שהמציאו את var היא מכיוון שבלעדיה אי אפשר היה להגדיר ולהשתמש ב – Anonymous Types, כמובן שאפשר היה להשתמש ב – object (מה שאנחנו צריכים לעשות במידה ונרצה לשלוח את המשתנה למתודה אחרת) אבל במקרה כזה הגישה למאפיינים היא רק בעזרת reflection שזה לא יעיל כמובן.
בנוסף אפשר לכתוב קוד כזה:
class MyClass { public int Age { get; set; } public string Name { get; set; } } class YourClass { public float Salary { get; set; } } MyClass mc1 = new MyClass(); YourClass yc1 = new YourClass(); var pi1 = new { mc1.Age, mc1.Name, yc1.Salary };
כמו שאפשר לראות אפשר להגדיר את מאפייני הטיפוס האנונימי מבלי לתת להם שם במפורש והם יקבלו את השם מהמאפיין שהם לוקחים את הערך שלו.
לכאורה כל הסיפור הזה נראה מיותר – בהמשך כשנלמד LINQ נראה שלפעמים אין ברירה וחייבים להשתמש בתחביר הזה.
Extension Methods
נניח שיש מחלקה שלא אנחנו כתבנו (כמו string) ואנחנו רוצים להרחיב אותה (כלומר להוסיף לה פונקציות) נוכל כמובן לרשת ממנה (במקרה של string אי אפשר – זוהי דוגמא) אבל במקרה הזה בכל מקום באפליקציה שלנו נצטרך להשתמש בטיפוס שלנו וכמובן מה קורה אם באמת רוצים להוסיף ל – string שכאמור אי אפשר לרשת ממנה, בשביל זה יש את ה – Extension Methods, לדוגמא:
static class StringExtension { public static int ToInt(this string s) { return int.Parse(s); } }
וכעת נוכל לכתוב
int num = Console.ReadLine().ToInt();
מכיוון ש – ReadLine מחזיר אובייקט מסוג string וכל אובייקט מסוג string קיבל מתודה חדשה שנקראת ToInt.
זה מאוד נוח ונותן לנו את היכולת להוסיף פונקציונאליות לאובייקטים שלא אנחנו כתבנו ומשתמשים בה ברחבי המערכת.
כדי שפונקציה תתווסף לטיפוס מסוים צריך לעשות את הדברים הבאים:
- להגדיר מחלקה סטטית.
- להגדיר מתודה סטטית שהפרמטר הראשון שלה מוגדר עם this וכל המופעים של הטיפוס שלו (הפרמטר הראשון) יקבלו את המתודה החדשה.
- ה – namespace שבו הוגדרה המתודה החדשה צריכה להיות מוגדרת בקובץ שבו רוצים להשתמש במתודה החדשה, כלומר אם המחלקה הסטטית תוגדר ב – namespace בשם a ובקובץ אחר באפליקציה לא יהיה using ל – a המתודה החדשה לא תופיע, כדי לגרום לכך שלא יצטרכו באמת להוסיף using שונים אפשר להגדיר namespace בשם MyExtension ותחתיו להגדיר את כל המחלקות החדשות, אופציה נוספת היא לתת את ה – namespace של המערכת למשל – אם מדובר בתוספות ל – string לעטוף את המחלקה ב – namespace של system וכן הלאה.
Lambda Expressions
בגרסאות הראשונות של השפה במידה והשתמשנו ב – delegate היינו צריכים לכתוב מתודה מיוחדת לשליחה, לדוגמא
static void Print(int number) { Console.WriteLine(number); } Actionaction = new Action (Print); action(10);
(כמובן שלא היה קיים generic אבל לצורך המחשת נושא ה-delegate נניח שהיה קיים).
במידה ורצינו להשתמש ב-delegate של Action היינו צריכים להגדיר מתודה שעומדת בחתימה ולשלוח אותה כפרמטר ל-ctor של ה-delegate.
בגרסה 2.0 של השפה קבלנו את המושג של anonymous methods ויכולנו לכתוב קוד כזה.
Actionaction = delegate(int num1) { Console.WriteLine(num1); }; action(10);
הסיבה המרכזית לתמיכה ב-anonymous methods היא היכולת להשתמש במשתנים לוקליים של הפונקציה שקוראת ל-delegate לדוגמא:
int userNum = int.Parse(Console.ReadLine()); Actionaction = delegate(int num1) { if (userNum == 10) num1++; Console.WriteLine(num1); }; action(10);
בגרסאות הקודמות של השפה שימוש במשתנה userNum היה מחייב להגדיר אותו כמשתנה גלובלי של המחלקה לעומת זאת החל מגרסה 2.0 ניתן להשתמש בכל המשתנים הלוקליים של הפונקציה שמפעילה את אותו delegate
החל מהגרסאות המתקדמות של השפה ניתן לכתוב Lambda Expressions שזהו תחביר אחר ל – anonymous methods (אחרי קומפילציה קיים רק anonymous methods) לדוגמא:
Actionaction1 = num1 => Console.WriteLine(num1); Action action2 = num1 => { if (userNum == 10) num1++; Console.WriteLine(num1); };
נפרק את השורה.
Actionaction1 = num1 => Console.WriteLine(num1);
השורה הראשונה זה כמובן המופע של ה – delegate,
השורה השנייה מכילה את רשימת הפרמטרים, במידה ויש יותר מפרמטר אחד צריך לעטוף אותם בסוגריים, לאחר רשימת הפרמטרים יש הסימון המוזר של <=,
השורה השלישית מכילה את הקוד עצמו, במידה ויש רק שורה אחת לא צריך סוגריים מסולסלות ואם ה-delegate אמור להחזיר ערך לא צריך לכתוב את המילה return, למשל:
Funcmul = num1 => num1 * 10; int res = mul(50);
הגדרנו מופע של delegate שאמור לקבל מספר ויכפיל אותן ב-10 ולאחר מכן הפעלנו אותו, וכמו שאפשר לשים לב אין צורך לכתוב את המילה return.
פורסם במקור בבלוג של שלמה גולדברג (הרב דוטנט) – מרצה ויועץ במכללת סלע
תגובות בפייסבוק