Nota
O acceso a esta páxina require autorización. Pode tentar iniciar sesión ou modificar os directorios.
O acceso a esta páxina require autorización. Pode tentar modificar os directorios.
Nota:
Este contenido se vuelve a imprimir con el permiso de Pearson Education, Inc. de Directrices de diseño de frameworks: Convenciones, expresiones y patrones para bibliotecas reutilizables de .NET, 2ª Edición. Esa edición fue publicada en 2008, y el libro ha sido totalmente revisado en la tercera edición. Parte de la información de esta página puede estar obsoleta.
Cualquier tipo diseñado específicamente para manipular un grupo de objetos que tienen alguna característica común se puede considerar una colección. Casi siempre es adecuado para estos tipos implementar IEnumerable o IEnumerable<T>, por lo que en esta sección solo se tienen en cuenta los tipos que implementan una o ambas interfaces para ser colecciones.
❌ NO utilice colecciones de tipo débil en las API públicas.
El tipo de todos los valores devueltos y parámetros que representan los elementos de colección debe ser el tipo de elemento exacto, no ninguno de sus tipos base (esto solo se aplica a los miembros públicos de la colección).
❌ NO use ArrayList ni List<T> en las APIs públicas.
Estos tipos son estructuras de datos diseñadas para usarse en la implementación interna, no en las API públicas.
List<T> está optimizado para el rendimiento y la eficiencia a costa de la claridad de las APIs y la flexibilidad. Por ejemplo, si devuelve List<T>, nunca podrá recibir notificaciones cuando el código de cliente modifique la colección. Además, List<T> expone muchos miembros, como BinarySearch, que no son útiles o aplicables en muchos escenarios. En las dos secciones siguientes se describen los tipos (abstracciones) diseñados específicamente para su uso en las API públicas.
❌ NO use Hashtable ni Dictionary<TKey,TValue> en las APIs públicas.
Estos tipos son estructuras de datos diseñadas para usarse en la implementación interna. Las API públicas deben usar IDictionary, IDictionary <TKey, TValue>o un tipo personalizado que implemente una o ambas interfaces.
❌ NO use IEnumerator<T>, IEnumerator ni ningún otro tipo que implemente cualquiera de estas interfaces, excepto como el tipo de retorno de un GetEnumerator método.
Los tipos que devuelven enumeradores de métodos distintos de GetEnumerator no se pueden usar con la foreach instrucción .
❌ NO implemente ni IEnumerator<T> ni IEnumerable<T> en el mismo tipo. Lo mismo se aplica a las interfaces IEnumerator no genéricas y IEnumerable.
Parámetros de recolección
✔️ Use el tipo menos especializado posible como tipo de parámetro. La mayoría de los miembros que toman colecciones como parámetros usan la IEnumerable<T> interfaz .
❌ EVITE usar ICollection<T> o ICollection como parámetro solo para tener acceso a la Count propiedad .
En su lugar, considere la posibilidad de usar IEnumerable<T> o IEnumerable y comprobar dinámicamente si el objeto implementa ICollection<T> o ICollection.
Propiedades de colección y valores devueltos
❌ NO proporcione propiedades de colección configurables.
Los usuarios pueden reemplazar el contenido de la colección borrando primero la colección y, a continuación, agregando el nuevo contenido. Si reemplazar toda la colección es un escenario común, considere proporcionar el método AddRange para la colección.
✔️ Utilice Collection<T> o una subclase de Collection<T> para propiedades o valores devueltos que representen colecciones de lectura y escritura.
Si Collection<T> no cumple algún requisito (por ejemplo, la colección no debe implementar IList), use una colección personalizada mediante la implementación IEnumerable<T>de , ICollection<T>o IList<T>.
✔️ Usa ReadOnlyCollection<T>, una subclase de ReadOnlyCollection<T>, o, en raras ocasiones, IEnumerable<T> para propiedades o valores devueltos que representen colecciones de solo lectura.
En general, prefiera ReadOnlyCollection<T>. Si no cumple algún requisito (por ejemplo, la colección no debe implementar IList), use una colección personalizada mediante la implementación IEnumerable<T>de , ICollection<T>o IList<T>. Si implementa una colección de solo lectura personalizada, implemente ICollection<T>.IsReadOnly para devolver true.
En los casos en los que esté seguro de que el único escenario que desee admitir es la iteración en una única dirección, simplemente puede usar IEnumerable<T>.
✔️ CONSIDERE la posibilidad de usar subclases de colecciones base genéricas en lugar de usar directamente las colecciones.
Esto permite un nombre más adecuado y también agregar miembros auxiliares que no están presentes en los tipos de colección base. Esto es especialmente aplicable a las API de alto nivel.
✔️ CONSIDERE la posibilidad de devolver una subclase de Collection<T> o ReadOnlyCollection<T> de métodos y propiedades muy usados.
Esto le permitirá agregar métodos auxiliares o cambiar la implementación de la colección en el futuro.
✔️ CONSIDERE la posibilidad de usar una colección con claves si los elementos almacenados en la colección tienen claves únicas (nombres, identificadores, etc.). Las colecciones con claves son colecciones que se pueden indizar mediante un entero y una clave y normalmente se implementan heredando de KeyedCollection<TKey,TItem>.
Las colecciones con claves suelen tener superficies de memoria mayores y no deben usarse si la sobrecarga de memoria supera las ventajas de tener las claves.
❌ NO devuelva valores NULL de propiedades de colección o de métodos que devuelven colecciones. Devuelve una colección vacía o una matriz vacía en su lugar.
La regla general es que las colecciones o matrices null y vacías (de 0 elementos) deben tratarse de la misma manera.
Instantáneas frente a colecciones dinámicas
Las colecciones que representan un estado en algún momento dado se denominan colecciones de instantáneas. Por ejemplo, una colección que contiene filas devueltas desde una consulta de base de datos sería una instantánea. Las colecciones que siempre representan el estado actual se denominan colecciones activas. Por ejemplo, una colección de ComboBox elementos es una colección dinámica.
❌ NO devuelva colecciones de instantáneas de las propiedades. Las propiedades deben devolver colecciones dinámicas.
Los captadores de propiedades deben ser operaciones muy ligeras. Devolver una instantánea requiere la creación de una copia de una colección interna en una operación de O(n).
✔️ USE una colección de instantáneas o un activo IEnumerable<T> (o su subtipo) para representar colecciones volátiles (es decir, que pueden cambiar sin modificar explícitamente la colección).
En general, todas las colecciones que representan un recurso compartido (por ejemplo, los archivos de un directorio) son volátiles. Estas colecciones son muy difíciles o imposibles de implementar como colecciones en tiempo real, a menos que la implementación sea simplemente un enumerador que solo avanza.
Elegir entre matrices y colecciones
✔️ PREFIERE colecciones sobre matrices.
Las colecciones proporcionan más control sobre el contenido, pueden evolucionar con el tiempo y son más utilizables. Además, no se recomienda usar matrices para escenarios de solo lectura porque el costo de clonación de la matriz es prohibitivo. Los estudios de facilidad de uso han demostrado que algunos desarrolladores se sienten más cómodos con las API basadas en colecciones.
Sin embargo, si está desarrollando API de bajo nivel, es posible que sea mejor usar matrices para escenarios de lectura y escritura. Las matrices tienen una superficie de memoria más pequeña, lo que ayuda a reducir el conjunto de trabajo y el acceso a los elementos de una matriz es más rápido porque está optimizado por el tiempo de ejecución.
✔️ CONSIDERE la posibilidad de usar matrices en API de bajo nivel para minimizar el consumo de memoria y maximizar el rendimiento.
✔️ Use matrices de bytes en lugar de colecciones de bytes.
❌ NO use matrices para propiedades si la propiedad tendría que devolver una nueva matriz (por ejemplo, una copia de una matriz interna) cada vez que se llama al captador de propiedades.
Implementación de colecciones personalizadas
✔️ CONSIDERE la posibilidad de heredar de Collection<T>, ReadOnlyCollection<T>o KeyedCollection<TKey,TItem> al diseñar nuevas colecciones.
✔️ Realice la implementación IEnumerable<T> al diseñar nuevas colecciones. Considere la posibilidad de implementar ICollection<T> o incluso IList<T> donde tenga sentido.
Al implementar dicha colección personalizada, siga el patrón de API establecido por Collection<T> y ReadOnlyCollection<T> lo más cerca posible. Es decir, implemente los mismos miembros explícitamente, nombre los parámetros de manera similar a como se nombran estas dos colecciones, y así sucesivamente.
✔️ CONSIDERE la posibilidad de implementar interfaces de colección no genéricas (IList y ICollection) si la colección a menudo se pasará a las API que toman estas interfaces como entrada.
❌ EVITE implementar interfaces de recopilación en tipos con API complejas no relacionadas con el concepto de una colección.
❌ NO herede de colecciones base no genéricas como CollectionBase. Use Collection<T>, ReadOnlyCollection<T>y KeyedCollection<TKey,TItem> en su lugar.
Nombrar colecciones personalizadas
Las colecciones (tipos que implementan IEnumerable) se crean principalmente por dos motivos: (1) para crear una nueva estructura de datos con operaciones específicas de estructura y a menudo diferentes características de rendimiento que las estructuras de datos existentes (por ejemplo, List<T>, LinkedList<T>, ), Stack<T>y (2) para crear una colección especializada para contener un conjunto específico de elementos (por ejemplo, StringCollection). Las estructuras de datos se usan con más frecuencia en la implementación interna de aplicaciones y bibliotecas. Las colecciones especializadas se exponen principalmente en las API (como tipos de propiedades y parámetros).
✔️ Debe usar el sufijo "Dictionary" en los nombres de las abstracciones que implementan IDictionary o IDictionary<TKey,TValue>.
✔️ Debes usar el sufijo "Collection" en nombres de tipos que implementan IEnumerable (o cualquiera de sus descendientes) y representan una lista de elementos.
✔️ Use el nombre de estructura de datos adecuado para las estructuras de datos personalizadas.
❌ EVITE usar los sufijos que impliquen una implementación determinada, como "LinkedList" o "Hashtable", en nombres de abstracciones de colección.
✔️ CONSIDERE la posibilidad de prefijar los nombres de colección con el nombre del tipo de elemento. Por ejemplo, una colección que almacena elementos de tipo Address (implementación IEnumerable<Address>) debe denominarse AddressCollection. Si el tipo de elemento es una interfaz, se puede omitir el prefijo "I" del tipo de elemento. Por lo tanto, se puede llamar IDisposablea una colección de DisposableCollection elementos .
✔️ CONSIDERE la posibilidad de usar el prefijo "ReadOnly" en nombres de colecciones de solo lectura si se puede agregar una colección que se puede escribir correspondiente o ya existe en el marco.
Por ejemplo, una colección de solo lectura de cadenas debe llamarse ReadOnlyStringCollection.
© Partes 2005, 2009 de Microsoft Corporation. Todos los derechos reservados.
Reimpreso con permiso de Pearson Education, Inc. de Framework Design Guidelines: Convenciones, Idiomas y Patrones para Bibliotecas .NET Reusables, 2ª Edición por Krzysztof Cwalina y Brad Abrams, publicado el 22 de octubre de 2008 por Addison-Wesley Professional como parte de la Serie Desarrollo de Microsoft Windows.