45. Lambda expressions

ראינו בפעמים הקודמות מה זה Anonymous delegates ואיך משתמשים בהם.

הבעיה העיקרית שאנחנו נתקלים בה היא שכתיבה של Anonymous delegate היא קצת זוועתית, למשל אפילו בדוגמה הכי פשוטה שראינו ביום ראשון, היינו צריכים לכתוב משהו כזה:

1
2
3
Console.WriteLine(First(numbers,
delegate(int number)
{ return (number % 2 == 0); })); // Prints 15

או כזה:

1
2
3
4
5
Predicate<int> isOdd =
delegate(int number)
{ return (number%2 == 0); };
Console.WriteLine(First(numbers, isOdd)); // Prints 15

בC# 3.0 הגיעו למסקנה שזה פוגע בקריאות וגורם לאנשים לסלוד משימוש בAnonymous delegates.

לכן באו והציגו את הפתרון באמצעות Lambda Expressions.


מה זה Lambda Expression? מדובר על גישה כללית שמגיעה מתחום הלוגיקה המתמטית שנקראת תחשיב למבדא.

אחת המטרות היא לצמצם את כתיבת הגדרת פונקציות בצורה פורמלית.

בC# זה בא לידי ביטוי כך:

נוכל לכתוב במקום

1
2
3
Predicate<int> isOdd =
delegate(int number)
{ return (number%2 == 0); };

כך:

1
2
3
Predicate<int> isOdd =
(int number) =>
{ return (number%2 == 0); };

אלא שאפשר עדיין להתווכח ולומר שהביטוי לא קריא.

גילו שמסתבר שככל שמציינים פחות, הביטוי נהיה יותר קריא. למשל מאחר והחתימה של הdelegate נראית כך:

1
public delegate bool Predicate<T>(T item);

אין צורך שנציין את הסוג של הארגומנט בשני הצדדים, אלא הקומפיילר יגלה את זה implicity בזמן בקימפול.

אז הביטוי נהפך להיות כזה:

1
2
3
Predicate<int> isOdd =
(number) =>
{ return (number%2 == 0); };

בנוסף, בגלל שמדובר בפרמטר אחד, מותר לנו להשמיט את הסוגריים סביבו:

1
2
3
Predicate<int> isOdd =
number =>
{ return (number%2 == 0); };

לבסוף, בגלל שיש לנו שורת קוד אחת, והיא של return, נוכל גם להסיר את הסוגריים ואת הreturn:

1
2
Predicate<int> isOdd =
number => (number%2 == 0);

הביטוי נהיה מאוד פשוט והרבה יותר קריא!


קצת על כתיבה של Lambda expressions:

בד"כ לא נצטרך לציין את סוגי הפרמטרים, אלא רק לתת להם שמות. אם מדובר על יותר מפרמטר אחד, נצטרך לשים סביב הפרמטרים סוגריים:

למשל אם יש לנו את הdelegate הזה:

1
public delegate int AddDelegate(int first, int second);

נוכל להציב לתוכו את הביטוי הבא:

1
AddDelegate add = (x, y) => x + y;

אם מדובר על delegate שלא מקבל פרמטרים, גם נצטרך לשים סוגריים:

1
2
3
public delegate string StringDelegate();
StringDelegate stringDelegate =
() => DateTime.Now.ToString();

שימו לב לסוגריים הריקים.

גם אם יש לנו חתימה שלא מחזירה ערך נוכל להשתמש בצורת כתיבה של שורה אחת:

1
2
3
4
public delegate void PrintDelegate(string output);
PrintDelegate printDelegate =
x => Console.WriteLine(x);

לבסוף, אם יש לנו מימוש של יותר משורה אחת, עדיין נוכל להשתמש בLambda Expression, אבל עם סוגריים מסולסלים:

1
2
3
4
5
6
AddDelegate add =
(x, y) =>
{
double z = Math.Sqrt(x*x + y*y);
return Convert.ToInt32(z);
};

שימו לב שזה עדיין יותר קריא מהכתיב של anonymous methods.

סופ"ש אנונימי מצוין

שתף