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?


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.


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.


-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.


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>.


IReadOnlyListbrzmi dobrze, kiedy mogę zdobyć VS2013, dzięki!
Matthew
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.