2009-02-20 7 views
3

Habituellement mes méthodes sont comme suit:Les meilleures pratiques lors du retour d'un tableau de valeurs (.NET)

public List<int> Method1(int input) 
{ 
    var output = new List<int>(); 
    //add some items to output 
    return output; 
} 

Mais une autre mise en œuvre FxCop conseille IList au lieu de la liste, mais je ne sais plus. Les alternatives comprennent le retour comme un IList, ICollection ou IEnumerable pour plus de flexibilité ou d'une toute autre façon que le code ci-dessous .:

public int[] Method2(int input) 
{ 
    var output = new List<int>(); 
    //add some items to output 
    return output.ToArray(); 
} 

de toutes les alternatives, tous fournis et toutes les possibilités, ce qui est considéré comme la meilleure pratique?

Répondre

5

"Framework Design Guidelines" (2e éd) dans §8.3.1 a beaucoup de choses à dire au sujet de collections comme valeurs de retour, résumé:

  • NE PAS possèdent des propriétés de collecte définissables.
  • DO d'utiliser Collection<T> ou une sous-classe de Collection<T> pour les propriétés ou les valeurs de retour représentant des collections de lecture/écriture.
  • DO utilisation ReadOnlyCollection<T>, une sous-classe de ReadOnlyCollection<T>, ou dans de rares cas IEnumerable<T> pour les propriétés ou renvoient des valeurs représentant en lecture seule collections.

(et plus, mais ces trois capturent le noyau). Le premier de ceux ci-dessus: ne renvoie pas de référence à la collection interne à moins que vous vouliez que l'utilisateur puisse le changer (et alors probablement vous devriez avoir un type personnalisé ainsi vous avez un degré de contrôle).

Je retournerais IList<T> et je m'assurerais de ne pas définir le type réel que je retourne, sauf si je retournais un itérateur (quand j'utiliserais IEnumerable<T>).

6

IEnumerable/IEnumerable < T> sauf si vous avez besoin spécifiquement une liste, vous devez retourner IList < T>

+0

Je suis d'accord, mais pouvez-vous développer pourquoi? – mmcdole

+0

Parce qu'il vous permet de modifier les détails d'implémentation à l'intérieur de la fonction, si nécessaire, sans casser le code qui appelle la fonction. –

+0

Par exemple, peut-être en ce moment vous renvoyez un tableau, mais à un moment donné dans le futur vous mettez à jour le code pour retourner une liste à la place. Si tout ce que vous avez promis est que vous retournez IEnumerable , le code d'appel fonctionnera tout à fait correctement. –

2

Retour à l'interface que vous avez besoin dans le code appelant cette méthode.

Si vous devez effectuer des actions de liste sur le résultat, renvoyez IList<T>. Si vous avez juste besoin d'énumérer les résultats, retournez IEnumerable<T>.

Ce sont ceux que j'utilise le plus, en fait. Je ne renvoie jamais de tableaux à partir d'interfaces publiques à moins d'une très bonne raison.

3

ReadOnlyCollection<T> est une autre option.

+0

Mais seulement si vous ne voulez pas donner à l'appelant la possibilité de mettre à jour la liste. De toute façon +1 à votre réponse. –

1

Cela dépend.

Voulez-vous que l'appelant puisse modifier les éléments et que vous voyiez ces changements? Les tableaux peuvent être modifiés. L'interface IList définit les méthodes de modification (mais l'implémentation peut ne pas l'autoriser).

Pouvez-vous élaborer sur l'avertissement FxCop?

Kent

+0

FxCop vous recommande de retourner un ReadOnlyCollection au lieu de la liste –

+0

Cela semble. . . impair. Comme je l'ai dit, que faire si vous voulez que les appelants puissent modifier le contenu? –

+0

« Ne pas exposer Liste dans les modèles d'objets. Utilisez Collection , ReadOnlyCollection ou KeyedCollection à la place. Liste est destiné à être utilisé de la mise en œuvre, et non pas dans l'API du modèle objet. Liste est optimisé pour une performance au prix d'une longue terme versioning .... –

1

Cela dépend de vos besoins. Tout compte fait, l'itération à travers des tableaux fortement typés est la plus rapide parmi tous les types de collection. Si vous n'avez pas besoin de redimensionner/ajouter/rechercher à travers eux, les tableaux sont assez bien.

1

Je vais presque toujours avec List parce qu'il me donne des méthodes que je trouve souvent les plus utiles. Une conséquence négative potentielle du renvoi d'un IEnumerable est que toutes les exceptions qui sont levées lors de l'énumération proviendraient d'une zone de code qui pourrait être assez éloignée du code qui a réellement construit l'objet, rendant le suivi des bogues plus difficile.

+0

La liste est pratique avant LINQ pour des choses comme "Find", mais post-3.5 ne vous donne rien que vous ne pouvez pas obtenir des méthodes d'extension IEnumerable standard. –

5

Eric Lippert a un bon post sur pourquoi returning an array is usually a bad idea. En règle générale, vous devriez être aussi général que vous pouvez être sans causer de chagrin indu à celui qui va appeler votre méthode. Préférez les interfaces aux classes concrètes et choisissez l'interface la plus générique avec laquelle vous pouvez vous en sortir. Les interfaces de retour encapsulent mieux votre implémentation et faciliteront les choses à l'avenir. Si vous commencez avec un type concret, vous êtes engagé à toujours renvoyant ce type.

IEnumerable<T> est le meilleur endroit pour commencer. Avec l'avènement de LINQ, il y a très peu de choses qu'un appelant ne peut pas faire facilement juste donné une énumération. Si un appelant a parfois besoin d'une liste, il est assez facile d'appeler le .ToList().

Si les appelants sont susceptibles d'avoir un besoin spécifique d'indexer dans la collection retournée, ou s'ils vont probablement vouloir modifier eux-mêmes la collection (insertion/suppression/réorganisation d'éléments), utilisez un IList<T>.

Questions connexes