11
votes

Lequel préférez-vous pour les interfaces: T [], iEnumerable , ilist ou autre?

OK, j'espère que la communauté en général aidera à résoudre un débat sur le lieu de travail en cours depuis un certain temps. Cela concerne la définition d'interfaces acceptant ou renvoyer des listes de caractères. Il y a plusieurs façons de faire cela: xxx pré>

ma propre préférence est d'utiliser iEnumerable pour les arguments et les tableaux pour les valeurs de retour: P>

public interface Foo
{
    void Do(IEnumerable<Bar> bars);
    Bar[] Bars { get; }
}


1 commentaires

J'ai vu les erreurs de mes manières. Autant d'Etat en dessous de ses développeurs, les développeurs évidents ne voient pas les propriétés [] comme immuables. Je suppose que mes abus d'eux m'ont appris de mauvaises habitudes. Je n'ai jamais vraiment soigné s'ils ont modifié la matrice puisqu'il s'agissait d'une copie; Cependant, je suis venu à réaliser la confusion qu'elle produit. IEnumerable est un gagnant de mains de mains que je pense.


8 Réponses :


18
votes

Ma préférence est ienumerable . Toute autre des interfaces suggérées donne l'apparition de permettre au consommateur de modifier la collection sous-jacente. Ce n'est certainement pas ce que vous voulez faire car il permet aux consommateurs de modifier silencieusement une collection interne.

Un autre bon iMho, est Readonlycollection . Il permet à toutes les propriétés amusantes et indexer et indique sans ambiguïté au consommateur "Vous ne pouvez pas modifier mes données".


11 commentaires

+1 Dans n'importe quelle application, j'ai travaillé sur, au moins, ienumerable est tout ce dont vous avez besoin de 98% du temps.


Ne pas dire que vous avez tort, mais cela ne suppose pas que vous ne réduisez pas une liste réadonnée ou une copie peu profonde (ou sans immuable)?


@annakata, mais comment exprimer cela à vos consommateurs? Vous ne pouvez pas simplement regarder un retour d'IList et savoir: 1) Devrais-je ne pas modifier cela, 2) est la modification désactivée en lancant (Dictionnaire :: Valeurs) ou 3) Être renvoyé une copie complète. Ce n'est tout simplement pas évident de l'utilisation. Renvoyer iEnumerable Par contre, assez sans ambiguïté, dit «vous ne touchez pas mes données».


Ne copiez-vous toujours pas la liste Membre de la mise en œuvre à un tableau d'abord? Si vous ne les risquez pas, vous risquez d'énumérer après modification à l'original. Cela ne mentionne pas le fait qu'ils peuvent lancer la liste et modifier l'instance privée.


@Jared: Vous mettez un contractuel.ensures (contracter.Result > (). Isreadonly) dans les catégories contractuelles;)


@Jon bonne idée. Mon plus gros problème avec les contrats est leur visibilité dans l'IDE (ils devraient être mieux mis en évidence). Encore une fois, je travaille sur une équipe IDE si ...


@Jarededpar: En effet. Bien sûr, si nous pouvions obtenir une vérification statique dans l'édition Visual Studio Non-Team-System, cela aiderait aussi ... :) Juste pour le garder pertinent: mon objection à Readonlycollection est-ce Il la reproche à un type de collection très particulier. J'ai popsicleliste comme une autre collection en lecture seule (une mutable mais peut alors être "gelée" avant de le donner; un peu comme une chaîne). Ce serait bien de disposer d'une interface de ces types pourraient mettre en œuvre. (Certes popsiclelist n'est que immutaculable après la congélation, compliquant des choses ...)


@JOH, Kewl j'ai appris à apprendre quelque chose aujourd'hui ... j'avais totalement inconscient des contrats de code en 3.5. Je suppose que je reste laissé dans mon monde 2.0;)


@ csharpest.net je pense que les contrats de code sont le nouveau dans 4.0


Peut-être est peut-être iéalable pour les données qui sont par nature énumérées d'une manière paresseuse ... et réadonnycollection pour une liste pré-chargée, voir ma réponse à ce sujet.


@EGLASIUS: Non, utilisez simplement iEnumerable. Il n'y a plus de raison d'utiliser ReadOnlycollection (voir le commentaire de Jon ci-dessus, ainsi que sa réponse ici )



15
votes

Je ne retourne pas de tableaux - ils sont vraiment un type de retour terrible à utiliser lors de la création d'une API - si vous avez vraiment besoin d'une séquence mutable, utilisez le ilist ou ICollection < T> interface ou renvoyer une collection concrete à la place.

aussi je suggérerais que vous lisiez Les tableaux considérés comme un peu nocifs par Eric Lippert:

J'ai une question morale d'un auteur des manuels de langage de programmation le autre jour demandant mes opinions sur Si des programmeurs débutants ou non devrait apprendre à utiliser des tableaux.

plutôt que de répondre à cela question, je lui ai donné une longue liste de mon Opinions sur les tableaux, comment j'utilise tableaux, comment nous attendons des matrices pour être utilisé dans le futur, et ainsi de suite. Cette obtient un peu longtemps, mais comme Pascal, je n'a pas eu le temps de le rendre plus court.

Permettez-moi de commencer par dire quand vous ne devrait certainement pas utiliser des tableaux, et puis cire plus philosophique sur le avenir de la programmation moderne et de la rôle de la matrice dans le monde à venir.


0 commentaires

8
votes

Pour les collections de propriétés indexées (et les indices ont une signification sémantique nécessaire), vous devez utiliser readonlycollection (lecture seule) ou ilist ( lire écrire). C'est le plus flexible et expressif. Pour des collections non indexées, utilisez ienumerable (lecture seule) ou ICollection (lecture / écriture).

Les paramètres de la méthode doivent utiliser ienumerable sauf si elles doivent ajouter / supprimer des éléments à la collection ( icollection ) ou 2) nécessitent des index pour Objectifs sémantiques nécessitaires ( ilist ). Si la méthode peut bénéficier de la disponibilité de l'indexation (telle qu'une routine de tri), elle peut toujours utiliser comme ilist ou .tolist () quand cela échoue dans la mise en œuvre .


1 commentaires

+1 Pour utiliser ce qui est approprié pour le scénario ... Ce n'est vraiment pas 1 à régner, alors tout ... Une autre façon de dire que ReadOnlyCollection vs. IEnumerable est pré-chargée contre paresseux chargé.



1
votes

Je préférerais iEnumerable car il s'agit de la plus grande valise des interfaces donnant à l'utilisateur final la possibilité de redéfinir comme il le souhaite. Même si cela peut fournir à l'utilisateur une fonctionnalité minimale pour commencer (fondamentalement seulement l'énumération), il suffirait toujours de couvrir pratiquement tous les besoins, en particulier avec les méthodes d'extension, toarray (), tolis (), etc.


0 commentaires

1
votes

Je pense à cela en termes d'écriture du code le plus utile possible: code qui peut faire plus.

Mettez dans ces termes, cela signifie que j'aime accepter l'interface la plus faible possible comme arguments de méthode, car cela rend mon code utile à partir de plusieurs endroits. Dans ce cas, c'est un ienumerable . Avoir un tableau? Vous pouvez appeler ma méthode. Avoir une liste? Vous pouvez appeler ma méthode. Avoir un bloc Itérateur? Vous avez l'idée.

Cela signifie également que j'aime mes méthodes pour renvoyer l'interface la plus forte qui convient, de sorte que le code qui s'appuie sur la méthode peut facilement faire plus. Dans ce cas, ce serait ilist . Notez que cela ne signifie pas que je construirai une liste juste pour que je puisse le retourner. Cela signifie simplement que si je avez déjà certains qui implémentent ilist , je peux aussi bien l'utiliser.

Notez que je suis un peu non conventionnel en ce qui concerne les types de retour. Une approche plus typique consiste également à renvoyer également des types plus faibles des méthodes pour éviter de vous bloquer dans une implémentation spécifique.


3 commentaires

... si j'en ai déjà quelque chose qui implémente ilist , je peux aussi bien l'utiliser ... oui je vois votre point; Cependant, cela peut causer d'étranges effets secondaires. Il faut que l'enveloppe soit minimale dans une collection longeonlycollection ().


@ cshaparptest.net Si vous souagiez qu'un doit être emballé dans la collection Readonly, pourquoi reveniez-vous alors un tableau de votre Soi qui est loin d'être loodonly après que tout élément puisse être substitué de toute chose assignable au type donné.


Vous êtes correct ici; Mon croyance erronée était que ce serait évident que vous receviez une copie et qu'il ne serait pas de but de la modifier. J'admets que j'étais clairement faux là-bas par cette discussion ... elle ne m'a jamais eue que les gens feraient "foo.bars [0] = x" ou un tel bêtises. Quoi qu'il en soit, merci d'avoir aidé à m'éclairer +1 :)



0
votes

IEnumerable est très utile pour l'itération évaluée paresseuse, en particulier dans des scénarios qui utilisent la chaîne de méthode.

Mais comme type de retour pour un niveau d'accès à des données typique, une propriété de compte est souvent utile et je préférerais renvoyer une icollection avec une propriété de compte ou éventuellement iliste si je pense que les consommateurs typiques voudront utiliser un indexeur.

Il s'agit également d'une indication à l'appelant que la collection a été matérialisée. Et ainsi, l'appelant peut parcourir la collection renvoyée sans obtenir des exceptions à partir du niveau d'accès aux données. Cela peut être important. Par exemple, un service peut générer un flux (E.G. Savon) de la collection renvoyée. Il peut être gênant si une exception est lancée à partir de la couche d'accès aux données tout en générant le flux dû à une itération évaluée paresseuse, car le flux de sortie est déjà partiellement écrit lorsque l'exception est lancée.


0 commentaires

0
votes

Étant donné que les méthodes d'extension LINQ ont été ajoutées à IEnumerable , j'ai constaté que mon utilisation des autres interfaces a considérablement diminué; probablement autour de 80%. J'avais l'habitude d'utiliser la liste religieusement, car il s'agissait de méthodes acceptées des délégués pour une évaluation paresseuse comme la trouvaille, la suite, la recherche et l'exemple. Depuis cela est disponible sur les extensions System.Linq, j'ai remplacé toutes ces références avec des références iEnumerables .


0 commentaires

0
votes

Je n'irais pas avec une matrice, c'est un type qui permet une modification encore n'a pas encore ajouté / enlever ... un peu comme le pire du peloton. Si je veux autoriser des modifications, j'utiliserais un type qui prend en charge Ajouter / Supprimer.

Lorsque vous souhaitez empêcher les modifications, vous l'emballez déjà / la copie, donc je ne vois donc pas ce qui ne va pas avec un iéalable ou une collection de lecture réveil. J'irais avec la plus tard ... quelque chose que je n'aime pas sur iEnumerable, c'est que c'est paresseux de la nature, mais lorsque vous utilisez des données préchargées uniquement pour l'envelopper, appelant le code qui fonctionne avec elle tend à supposer données chargées ou avoir des lignes "inutiles" supplémentaires :( ... qui peuvent obtenir des résultats laids pendant le changement.


0 commentaires