Zwraca interfejs lub klasę

9

Załóżmy, że mam metodę

public List<User> GetBatchOfUsers(IEnumerable<int> userIDs)
{
    List<User> users = new List<User>();

    // some database stuff

    return users;
}

Przeczytałem, że lepiej byłoby zwrócić interfejs (albo IListalbo IEnumerable), niż zwrócić a List. Niektóre argumenty, które słyszałem, to to, że ukrywa dane i daje programistom API elastyczność zmiany wewnętrznej reprezentacji danych w późniejszym terminie.

Moją obawą przed zwrotem IEnumerablejest utrata funkcjonalności, takiej jak losowy dostęp i Countwłaściwość.

Wiem, że przyjęcie IEnumerableparametru jako parametru ma sens, ponieważ daje konsumentowi najlepszą elastyczność w wysyłaniu danych do mojej metody, minimalistycznego zestawu wymagań dla metody do działania.

Jaka jest najlepsza praktyka dla typu zwrotu?

Mateusz
źródło
5
O wiele ważniejsze: weź interfejs jako typ parametru.
Michael Borgwardt,

Odpowiedzi:

10

Ogólnie rzecz biorąc, możesz zacząć od interfejsów i przejść do umieszczenia konkretnego typu jako typu zwracanego, jeśli zauważysz, że korzystasz z dodatkowych metod częściej niż oczekiwano.

Cóż, jeśli zwrócisz interfejs, zachowasz większą elastyczność. Możesz zmienić implementację później, aby zwrócić inny konkretny typ. Z drugiej strony, w oczywisty sposób przekazuje dzwoniącemu mniej informacji, więc może nie być w stanie wykonać pewnych operacji. (Na przykład: jeśli wrócisz List<T>, dzwoniący może użyć ConvertAll itp. ... czego nie może, jeśli tylko zadeklarujesz, że wrócisz IList<T>.) W niektórych sytuacjach warto określić konkretny typ.

Jeśli chodzi o metodę Count lub Sort, nie ma do tego standardowych interfejsów kolekcji. Możesz jednak napisać metodę rozszerzenia, aby posortować lub policzyć dowolną IList.

Jusubow
źródło
To chyba nie jest trudna zasada?
Matthew
tak, to naprawdę zależy od użytkowania.
Yusubov,
1

Jeśli potrzebujesz swojej kolekcji, Countabyś mógł z niej korzystać ICollection<T>, co jest dość ogólne.

dpiatkowski
źródło
-1. Count był już dyskutowany i ta odpowiedź nie dodaje nic nowego
superM
@Konrad Rudolph, to nie jest odpowiedź, to komentarz.
superM
@superM Myślę, że jest wystarczająco cenny, aby zasłużyć na swoją własną odpowiedź, ponieważ w wyraźny sposób odnosi się do powodu, dla którego OP decyduje się na interfejsy w pierwszej kolejności.
Konrad Rudolph
1

Zwraca to, co jest ostrożne dla metody, którą definiujesz. Czy to, co robisz, zwracając serię przedmiotów (koncentrujesz się na przedmiotach), czy też zwracasz kolekcję przedmiotów (koncentrujesz się na kolekcji jako całości)? Czy warto pozwolić na wariancję w realizacji kolekcji? Jeśli to nie będzie sensu używać generatora lub HashSetpotem po prostu używać List.

Telastyn
źródło
1

Specyficzne dla przykładowej metody: Masz rację, że zwracanie IEnmuerable<T>oznaczałoby utratę funkcjonalności Counti indeksowania (chociaż możesz użyć metod LINQ Count()i ElementAt(), które są skutecznie zaimplementowane, jeśli typ, na którym są używane IList<T>).

Jeśli wrócisz IList<T>, stracisz trochę funkcjonalności, ale prawdopodobnie zyskujesz na ogólności.

Ale jeszcze lepiej byłoby coś pomiędzy IEnumerable<T>i IList<T>, ponieważ najprawdopodobniej nie ma sensu mutować zwracanej kolekcji przez konsumenta, ale ma sens użycie Countlub indeksowanie.

W .NET 4.5, istnieje taki interfejs: IReadOnlyList<T>.

svick
źródło
IReadOnlyListbrzmi dobrze, kiedy mogę zdobyć VS2013, dzięki!
Matthew