96. LINQ query syntax - where pitfall

נחשפנו פעם שעברה לQuery Syntax של LINQ.

נציג כעת Pitfall נפוץ בעבודה עם Query syntax.

לפעמים אנחנו כותבים שאילתא כזאת:

1
2
3
4
IEnumerable<Person> belowAverage =
from person in family
where person.Age <= AverageAge(family)
select person;

זו שאילתא שמוצאת את כל האנשים במשפחה שהגיל שלהם הוא קטן או שווה לממוצע של הגיל של המשפחה.

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

1
2
IEnumerable<Person> belowAverage =
family.Where(person => person.Age <= AverageAge(family));

עכשיו אם נזכר איך עובד Where:

1
2
3
4
5
6
7
8
9
10
11
12
public static IEnumerable<T> Where<T>
(this IEnumerable<T> enumerable,
Func<T, bool> predicate)
{
foreach (T current in enumerable)
{
if (predicate(current))
{
yield return current;
}
}
}

אז בעצם מתבצע קוד כזה:

1
2
3
4
5
6
7
8
9
10
11
public static IEnumerable<Person> FilterBelowAverage
(IEnumerable<Person> family)
{
foreach (Person person in family)
{
if (person.Age <= AverageAge(family))
{
yield return person;
}
}
}

מה שחשוב זו השורה בif. שימו לב שכל איטרציה מתבצע חישוב של הממוצע של הגיל של המשפחה. חישוב זה הוא סטטי לשאילתא, אבל מתבצע בכל פעם מחדש.

אם חישוב זה אורך זמן, זה גם עשוי לפגוע בצורה משמעותית בזמן הרצת השאילתא שלנו.

איך מתגברים על הpitfall הזה?

פשוט מחשבים את מה שסטטי לפני השאילתא:

1
2
3
4
5
6
int averageAge = AverageAge(family);
IEnumerable<Person> belowAverage =
from person in family
where person.Age <= averageAge
select person;

כך החישוב מתבצע פעם אחת לפני הרצת השאילתא, במקום להתבצע עבור כל איטרציה…

שבוע טוב שאילתא מובנית שפה טוב

שתף