Gdy pisałem ten kod przypomniałem sobie wielokrotnie widziany schemat w oprogramowaniu produkcyjnym. W moim przypadku wyglądałby on tak:
Widzisz różnicę? W metodzie AddExercise za każdym razem dokonywane jest sprawdzenie, które w kodzie IL wygląda następująco (zrzut z programu ILSpy zainstalowanego jako plugin do VS – polecam, ma pomocne informacje dot. składni) :
Widzimy, że kod odpowiedzialny za sprawdzenie, czy zmienna _exercises ma wartość null to co najmniej 8 instrukcji i może wpływać negatywnie na wydajność metody. O ile w naszym przypadku nie jest to żadna przeszkoda, wydajność plasuje się na jednym z ostatnich miejsc w wymaganiach naszego „klienta”, to mogę sobie wyobrazić, że dodajemy na przykład wartości sczytywane z setek tysięcy liczników energii elektrycznej i sprawdzenie to nagle zaczyna wpływać na działanie programu. A wystarczyłoby przecież zainicjować listę w konstruktorze, prawda? (Oczywiście TYLKO w przypadku,jeżeli lista jest prywatna, bądź ma prywatny setter lub gdy tylko my, jako twórcy, się nią posługujemy i nie zrobimy głupoty w stylu ustawienia listy na null – lepiej wtedy w ogóle zadeklarować ją jako private readonly z publicznym property getterem). Korzystając z okazji dodam jeszcze uwagę, czym różni się inicjacja pól klasy wewnątrz konstruktora i poza nim. Otóż w obydwu przypadkach wygenerowany kod IL jest taki sam:
W obu przypadkach lista jest inicjowana w konstruktorze i różni się jedynie kolejnością inicjacji listy i wołania konstruktora klasy bazowej Object.
Pociągnąłbym jeszcze temat w kierunku, czy i dlaczego inicjowanie kolekcji w konstruktorze jest lepsze od inicjowania przy deklaracji.
Postaram się przy najbliższej okazji:)