15. Enumerable.Any

לעתים קרובות יש לנו IEnumerable שמתקבל למשל משאילתת LINQ:

1
2
3
4
5
6
7
IEnumerable<string> fruits =
new []{"Apple", "Banana", "Peach", "Grapes", "Watermelon"};
IEnumerable<string> fruitQuery =
from fruit in fruits
where fruit.Length == 5
select fruit;

בד"כ אנחנו רוצים לבדוק אם חזרו תוצאות. הדרך הפופולארית הנהוגה לעשות זאת היא כך:

1
2
3
4
if (fruitQuery.Count() > 0)
{
// ...
}

אלא שדרך זו אינה יעילה, כיוון שהמימוש של הExtension Method של Count הוא כהלן:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static int Count<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw new ArgumentException("source");
}
ICollection<TSource> is2 = source as ICollection<TSource>;
if (is2 != null)
{
return is2.Count;
}
else
{
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
num++;
}
}
return num;
}
}

שימו לב:

אם ה IEnumerable<T>שהעברנו הוא ICollection<T> מתבצעת אופטימיזציה וזה ניגש לProperty בשם Count שלו.

אבל אחרת אנחנו עוברים על כל ה IEnumerable<T>בשביל לספור את כמות האיברים שבו, כשבסה"כ רצינו לבדוק שהוא אינו ריק.

בד"כ יקרה המקרה הגרוע, כיוון שמדובר בדרך כלל בתסריט של בדיקה האם מתקבלת תשובה משאילתת LINQ.

הפתרון הוא להשתמש בExtension Method שנקרא Any, כעת הif יראה כך:

1
2
3
4
if (fruitQuery.Any())
{
// ...
}

לו יש מימוש יותר פשוט ויעיל:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static bool Any<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw new ArgumentException("source");
}
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return true;
}
}
return false;
}

הערה אחרונה:

לAny יש גם overload שמקבל predicate ומחזיר תשובה האם קיים איבר שמקיים את הpredicate.

ראו גם טיפ מספר 156.5 לפתרון דומה לשאלה "האם IEnumerable מכיל לפחות x איברים?"

סופ"ש מצוין

שתף