Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Remarque
Ce contenu est réimprimé avec l’autorisation de Pearson Education, Inc. tiré de Lignes directrices de conception de framework : Conventions, Idiomes et Modèles pour les bibliothèques .NET réutilisables, 2ème édition. Cette édition a été publiée en 2008, et le livre a été entièrement révisé dans la troisième édition. Certaines informations de cette page peuvent être obsolètes.
Tout type conçu spécifiquement pour manipuler un groupe d’objets ayant une caractéristique commune peut être considéré comme une collection. Il est presque toujours approprié pour ces types d’implémenter IEnumerable ou IEnumerable<T>, donc dans cette section, nous considérons uniquement les types implémentant un ou les deux de ces interfaces comme des collections.
❌ N’utilisez PAS de collections faiblement typées dans les API publiques.
Le type de toutes les valeurs et paramètres de retour représentant des éléments de collection doit être le type d’élément exact, et non l’un de ses types de base (cela s’applique uniquement aux membres publics de la collection).
❌ NE PAS utiliser ArrayList ou List<T> dans les API publiques.
Ces types sont des structures de données conçues pour être utilisées dans l’implémentation interne, et non dans les API publiques.
List<T> est optimisé pour la performance et l'efficacité au détriment de la clarté des API et de la flexibilité. Par exemple, si vous retournez List<T>, vous ne pourrez jamais recevoir de notifications lorsque le code client modifie la collection.
List<T> Expose également de nombreux membres, tels que BinarySearch, qui ne sont pas utiles ou applicables dans de nombreux scénarios. Les deux sections suivantes décrivent les types (abstractions) conçus spécifiquement pour une utilisation dans les API publiques.
❌ NE PAS utiliser Hashtable ou Dictionary<TKey,TValue> dans les API publiques.
Ces types sont des structures de données conçues pour être utilisées dans l’implémentation interne. Les API publiques doivent utiliser IDictionary, IDictionary <TKey, TValue>ou un type personnalisé implémentant une ou les deux interfaces.
❌ NE PAS utiliser IEnumerator<T>, IEnumeratorou tout autre type qui implémente l’une de ces interfaces, à l’exception du type de retour d’une GetEnumerator méthode.
Les types qui retournent des énumérateurs à partir de méthodes autres que GetEnumerator ne peuvent pas être utilisés avec l'instruction foreach.
❌ N’implémentez PAS les deux IEnumerator<T> et IEnumerable<T> sur le même type. Cela s'applique également aux interfaces non génériques IEnumerator et IEnumerable.
Paramètres de collection
✔️ Utilisez le type le moins spécialisé possible comme type de paramètre. La plupart des membres qui acceptent des collections comme paramètres utilisent l’interface IEnumerable<T>.
❌ ÉVITEZ d’utiliser ICollection<T> ou ICollection en tant que paramètre simplement pour accéder à la Count propriété.
Au lieu de cela, envisagez d’utiliser IEnumerable<T> ou IEnumerable de vérifier dynamiquement si l’objet implémente ICollection<T> ou ICollection.
Propriétés de la collection et valeurs de retour
❌ Ne fournissez pas de propriétés de collection paramétrables.
Les utilisateurs peuvent remplacer le contenu de la collection en désactivant d’abord la collection, puis en ajoutant le nouveau contenu. Si le remplacement de la collection entière est un scénario courant, envisagez de fournir la AddRange méthode sur la collection.
✔️ Utilisez Collection<T> ou une sous-classe de Collection<T> pour les propriétés ou les valeurs de retour représentant des collections en lecture/écriture.
Si Collection<T> ne répond pas à certaines exigences (par exemple, la collection ne doit pas implémenter IList), utilisez une collection personnalisée en implémentant IEnumerable<T>, ICollection<T>, ou IList<T>.
✔️ Utilisez ReadOnlyCollection<T>, une sous-classe de ReadOnlyCollection<T>, ou dans de rares cas IEnumerable<T> pour les propriétés ou les valeurs de retour représentant des collections en lecture seule.
En général, préférez ReadOnlyCollection<T>. S’il ne répond pas à certaines exigences (par exemple, la collection ne doit pas implémenter IList), utilisez une collection personnalisée en implémentant IEnumerable<T>, ICollection<T>ou IList<T>. Si vous implémentez une collection en lecture seule personnalisée, implémentez ICollection<T>.IsReadOnly pour retourner true.
Dans les cas où vous êtes sûr que le seul scénario que vous souhaiterez prendre en charge est une itération vers l’avant uniquement, vous pouvez simplement utiliser IEnumerable<T>.
✔️ ENVISAGEZ d’utiliser des sous-classes de collections de base génériques au lieu d’utiliser directement les collections.
Cela permet d'utiliser un nom plus approprié et d'ajouter des membres supplémentaires qui ne sont pas présents dans les types de collection de base. Cela s’applique particulièrement aux API de haut niveau.
✔️ ENVISAGEZ de retourner une sous-classe de Collection<T> ou ReadOnlyCollection<T> à partir de méthodes et propriétés très couramment utilisées.
Cela vous permettra d’ajouter des méthodes d’assistance ou de modifier l’implémentation de collection à l’avenir.
✔️ ENVISAGEZ d’utiliser une collection à clés si les éléments stockés dans la collection ont des clés uniques (noms, ID, etc.). Les collections à clés sont des ensembles qui peuvent être indexés à la fois par un entier et une clé et qui sont généralement implémentés en héritant de KeyedCollection<TKey,TItem>.
Les collections à clés ont généralement des empreintes mémoire plus importantes et ne doivent pas être utilisées si une surcharge de mémoire dépasse les avantages de disposer de clés.
❌ NE RETOURNEZ PAS de valeurs Null à partir des propriétés de collection ou des méthodes retournant des collections. Retournez une collection vide ou un tableau vide à la place.
La règle générale est que les collections ou tableaux null et vides (0 élément) doivent être traités de la même façon.
Captures instantanées et collections dynamiques
Les collections représentant un état à un moment donné sont appelées collections d’instantanés. Par exemple, une collection contenant des lignes retournées à partir d’une requête de base de données serait un instantané. Les collections qui représentent toujours l’état actuel sont appelées collections dynamiques. Par exemple, une collection d’éléments ComboBox est une collection dynamique.
❌ NE RETOURNEZ PAS les collections d’instantanés à partir des propriétés. Les propriétés doivent retourner des collections actualisées.
Les accesseurs de propriété doivent être des opérations très légères. Le renvoi d’un instantané nécessite la création d’une copie d’une collection interne dans une opération O(n).
✔️ Utilisez une collection d’instantanés ou un sous-type actif IEnumerable<T> (ou son sous-type) pour représenter des collections volatiles (c’est-à-dire qui peuvent changer sans modifier explicitement la collection).
En général, toutes les collections représentant une ressource partagée (par exemple, les fichiers d’un répertoire) sont volatiles. Ces collections sont très difficiles ou impossibles à implémenter en tant que collections en temps réel, sauf si l’implémentation est simplement un énumérateur uniquement en avant.
Choix entre les tableaux et les collections
✔️ Préférez les collections aux tableaux.
Les collections offrent un contrôle plus élevé sur le contenu, peuvent évoluer au fil du temps et sont plus utilisables. En outre, l’utilisation de tableaux pour les scénarios en lecture seule est déconseillée, car le coût du clonage du tableau est prohibitif. Des études sur la facilité d’utilisation ont montré que certains développeurs se sentent plus à l’aise à l’aide d’API basées sur des collections.
Toutefois, si vous développez des API de bas niveau, il peut être préférable d’utiliser des tableaux pour les scénarios en lecture-écriture. Les tableaux ont une empreinte mémoire plus réduite, ce qui aide à diminuer l'ensemble mémoire utilisé. L'accès aux éléments d'un tableau est plus rapide, car il est optimisé par l'environnement d'exécution.
✔️ ENVISAGEZ d’utiliser des tableaux dans des API de bas niveau pour réduire la consommation de mémoire et optimiser les performances.
✔️ Utilisez des tableaux d’octets au lieu de collections d’octets.
❌ N’utilisez PAS de tableaux pour les propriétés si la propriété doit retourner un nouveau tableau (par exemple, une copie d’un tableau interne) chaque fois que le getter de propriété est appelé.
Implémentation de collections personnalisées
✔️ ENVISAGEZ d’hériter de Collection<T>, ReadOnlyCollection<T> ou KeyedCollection<TKey,TItem> lors de la conception de nouvelles collections.
✔️ Implémentez-le IEnumerable<T> lors de la conception de nouvelles collections. Envisagez d’implémenter ICollection<T> ou même là IList<T> où il est judicieux.
Lorsque vous implémentez une collection personnalisée, suivez le modèle d'API établi par Collection<T> et ReadOnlyCollection<T> le plus étroitement possible. C'est-à-dire, implémentez de manière explicite les mêmes membres, nommez les paramètres comme le sont ces deux collections, et ainsi de suite.
✔️ ENVISAGEZ d’implémenter des interfaces de collection non générées (IList et ICollection) si la collection sera souvent transmise aux API prenant ces interfaces comme entrée.
❌ ÉVITEz d’implémenter des interfaces de collection sur des types avec des API complexes qui ne sont pas liées au concept d’une collection.
❌ NE PAS hériter de collections de base non génériques telles que CollectionBase. Utilisez Collection<T>, ReadOnlyCollection<T>et KeyedCollection<TKey,TItem> à la place.
Affectation de noms à des collections personnalisées
Les collections (types qui implémententIEnumerable) sont créées principalement pour deux raisons : (1) pour créer une structure de données avec des opérations spécifiques à la structure et souvent différentes des caractéristiques de performances que les structures de données existantes (par exemple, List<T>, , LinkedList<T>Stack<T>et (2) pour créer une collection spécialisée pour contenir un ensemble spécifique d’éléments (par exemple, StringCollection). Les structures de données sont les plus souvent utilisées dans l’implémentation interne d’applications et de bibliothèques. Les collections spécialisées sont principalement exposées dans les API (en tant que types de propriétés et de paramètres).
✔️ Utilisez le suffixe « Dictionary » dans les noms d’abstractions implémentant IDictionary ou IDictionary<TKey,TValue>.
✔️ Utilisez le suffixe « Collection » dans les noms de types implémentant IEnumerable (ou l’un de ses descendants) et représentant une liste d’éléments.
✔️ Utilisez le nom de structure de données approprié pour les structures de données personnalisées.
❌ ÉVITEz d’utiliser des suffixes impliquant une implémentation particulière, telle que « LinkedList » ou « Hashtable », dans les noms d’abstractions de collection.
✔️ ENVISAGEZ de préfixer les noms de collection avec le nom du type d’élément. Par exemple, une collection stockant des éléments de type Address (implémentation IEnumerable<Address>) doit être nommée AddressCollection. Si le type d’élément est une interface, le préfixe « I » du type d’élément peut être omis. Ainsi, une collection d’éléments IDisposable peut être appelée DisposableCollection.
✔️ ENVISAGEZ d’utiliser le préfixe « ReadOnly » dans les noms des collections en lecture seule si une collection accessible en écriture correspondante peut être ajoutée ou existe déjà dans l’infrastructure.
Par exemple, une collection en lecture seule de chaînes doit être appelée ReadOnlyStringCollection.
Portions © 2005, 2009 Microsoft Corporation. Tous droits réservés.
Réimprimé par l’autorisation de Pearson Education, Inc. tiré de Framework Design Guidelines : Conventions, Idioms et Patterns pour les bibliothèques .NET réutilisables, 2e édition par Krzysztof Cwalina et Brad Abrams, publié le 22 octobre 2008 par Addison-Wesley Professional dans le cadre de la Série de développement Microsoft Windows.