Interface ou classe de retour

9

Supposons que j'ai une méthode

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

    // some database stuff

    return users;
}

J'ai lu qu'il serait préférable de renvoyer une interface (soit IListou IEnumerable) plutôt que de renvoyer a List. Certains arguments que j'ai entendus pour le faire sont qu'il cache les données et donne au développeur d'API la flexibilité de changer la représentation interne des données à une date ultérieure.

Mon souci de simplement renvoyer un IEnumerableest que vous perdez des fonctionnalités, telles que l'accès aléatoire et la Countpropriété.

Je sais qu'accepter un IEnumerablecomme paramètre est logique, car cela donne au consommateur la meilleure flexibilité pour envoyer des données à ma méthode, l'ensemble minimaliste d'exigences pour que la méthode fonctionne.

Quelle est la meilleure pratique pour le type de retour?

Matthieu
la source
5
Beaucoup plus important: prenez une interface comme type de paramètre.
Michael Borgwardt

Réponses:

10

De manière générale, vous pouvez commencer par les interfaces et ne déplacer pour placer le type concret comme type de retour que si vous constatez que vous utilisez les méthodes supplémentaires plus fréquemment que prévu.

Eh bien, si vous retournez une interface, vous conservez plus de flexibilité. Vous pouvez modifier l'implémentation ultérieurement pour renvoyer un type de béton différent. D'un autre côté, cela donne évidemment à l'appelant moins d'informations, de sorte qu'il peut ne pas être en mesure d'effectuer certaines opérations. (Par exemple: si vous retournez List<T>, l'appelant peut utiliser ConvertAll etc ... ce qu'il ne peut pas si vous déclarez seulement que vous retournez IList<T>.) Dans certaines situations, il convient de spécifier le type concret.

Concernant la méthode Count ou Sort, il n'y a pas d'interfaces de collecte standard pour cela. Cependant, vous pouvez écrire une méthode d'extension pour trier ou compter n'importe quel IList.

Yusubov
la source
Je suppose que ce n'est pas vraiment une règle difficile alors?
Matthew
oui, cela dépend vraiment de l'utilisation.
Yusubov
1

Si vous avez besoin que votre collection en ait une, Countvous pouvez l'utiliser ICollection<T>, ce qui est assez général.

dpiatkowski
la source
-1. Le compte a déjà été discuté et cette réponse n'ajoute rien de nouveau
superM
@Konrad Rudolph, ce n'est pas une réponse, c'est un commentaire.
superM
@superM Il est suffisamment précieux pour mériter sa propre réponse, je pense, car il aborde explicitement la raison pour laquelle OP se prononce contre les interfaces en premier lieu.
Konrad Rudolph
1

Vous retournez ce qui est prudent pour la méthode que vous définissez. Est-ce que vous faites le retour d'une série d'articles (l'accent est mis sur les articles) ou renvoie-t-il une collection d'articles (l'accent est mis sur la collection dans son ensemble)? Vaut-il la peine de permettre des écarts dans la mise en œuvre de la collection? Si cela n'a jamais de sens d'utiliser un générateur ou HashSetalors utilisez simplement le List.

Telastyn
la source
1

Spécifique à l'exemple de méthode: vous avez raison de dire que le retour IEnmuerable<T>signifierait que vous perdriez la fonctionnalité Countet l'indexation (bien que vous puissiez utiliser les méthodes LINQ Count()et ElementAt(), qui sont implémentées efficacement si le type sur lequel elles sont réellement implémentées IList<T>).

Si vous reveniez IList<T>, vous perdriez certaines fonctionnalités, mais le gain en général en vaut probablement la peine.

Mais encore mieux serait quelque chose entre IEnumerable<T>et IList<T>, car il est très peu probable que le consommateur mute la collection retournée, mais cela a du sens pour lui d'utiliser Countou d'indexer.

Dans .Net 4.5, il y a cette interface: IReadOnlyList<T>.

svick
la source
IReadOnlyListsonne bien quand je peux obtenir VS2013, merci!
Matthew