Code review: Pułapka z LINQ

Rozważmy następujący kod:

IEnumerable<Employee> employees=GetAllEmployees();
if (employees.Count() > 0)
{
    // jakis kod
}

Załóżmy, że chcemy wykonać jakiś kod jeśli istnieją w bazie pracownicy. Ponadto nie mamy pojęcia co dokładnie zwraca GetAllEmployees – wiemy, że jest to IEnumerable<Employee>. Jeśli jest to np. LINQ – SQL, rozwiązanie jest bardzo niewydajne. Lepiej zastąpić to metodą Any():

IEnumerable<Employee> employees=GetAllEmployees();
if (employees.Any())
{
    // jakis kod
}

Count musi pobrać liczbę wszystkich wierszy w bazie lub wykonać foreach po każdym obiekcie. Any wykonuje po prostu MoveNext i jeśli operacja udała się to znaczy, że istnieje przynajmniej jeden obiekt. W przypadku LINQ to Objects, nie ma to znaczenia ponieważ jest tam optymalizacja która zwraca .Length przy wywołaniu Count(). W praktyce jednak nigdy nie wiemy co może zwrócić nam metoda więc lepiej pisać od razu optymalny kod.

3 thoughts on “Code review: Pułapka z LINQ”

  1. Warto też pamiętać, że zapytanie jest wykonywane dopiero w momencie wywołania metody .Count() czy .Any(). Mało tego, w takiej sytuacji występuje prawdopodobieństwo większe od zera, że kolejne wywołanie metody count/tolist/todictionary etc… wykona zapytanie po raz kolejny. Dlatego też jeśli do danej kolekcji odwołujemy się więcej niż raz to warto od razu wywołać np ToList() (czyli deklaracja zmiennej wyglądałaby tak: var employees=GetAllEmployees().ToList()) aby kontrolować moment i liczbę wykonań zapytania.

  2. Generalnie wszystko co ma nawiasy (), jest metoda i nalezy sie spodziewac ze zawsze jest tam foreach. Count() != Count;

Leave a Reply

Your email address will not be published.