En la publicación del blog de Kathleen Dollard de 2008 , presenta una razón interesante para usar clases anidadas en .net. Sin embargo, también menciona que a FxCop no le gustan las clases anidadas. Supongo que las personas que escriben las reglas de FxCop no son estúpidas, por lo que debe haber un razonamiento detrás de esa posición, pero no he podido encontrarlo.
93
Respuestas:
Use una clase anidada cuando la clase que está anidando solo sea útil para la clase adjunta. Por ejemplo, las clases anidadas le permiten escribir algo como (simplificado):
Puede hacer una definición completa de su clase en un solo lugar, no tiene que pasar por los aros de PIMPL para definir cómo funciona su clase, y el mundo exterior no necesita ver nada de su implementación.
Si la clase TreeNode fuera externa, tendría que crear todos los campos
public
o crear un montón deget/set
métodos para usarla. El mundo exterior tendría otra clase contaminando su intellisense.fuente
Del tutorial de Java de Sun:
¿Por qué utilizar clases anidadas? Hay varias razones convincentes para usar clases anidadas, entre ellas:
Agrupación lógica de clases: si una clase es útil solo para otra clase, entonces es lógico incrustarla en esa clase y mantener las dos juntas. Anidar tales "clases auxiliares" hace que su paquete sea más ágil.
Mayor encapsulación: considere dos clases de nivel superior, A y B, donde B necesita acceso a miembros de A que de otra manera se declararían privados. Al ocultar la clase B dentro de la clase A, los miembros de A pueden declararse privados y B puede acceder a ellos. Además, el propio B puede ocultarse del mundo exterior.<- Esto no se aplica a la implementación de C # de clases anidadas, esto solo se aplica a Java.Código más legible y fácil de mantener: anidar clases pequeñas dentro de clases de nivel superior coloca el código más cerca de donde se usa.
fuente
Patrón singleton completamente Lazy y seguro para subprocesos
fuente: http://www.yoda.arachsys.com/csharp/singleton.html
fuente
Depende del uso. Rara vez usaría una clase pública anidada, pero uso clases privadas anidadas todo el tiempo. Se puede usar una clase anidada privada para un subobjeto que está destinado a usarse solo dentro del padre. Un ejemplo de esto sería si una clase HashTable contiene un objeto Entry privado para almacenar datos solo internamente.
Si la clase está destinada a ser utilizada por la persona que llama (externamente), generalmente me gusta convertirla en una clase independiente separada.
fuente
Además de las otras razones enumeradas anteriormente, hay una razón más en la que puedo pensar no solo en usar clases anidadas, sino también en clases públicas anidadas. Para aquellos que trabajan con múltiples clases genéricas que comparten los mismos parámetros de tipo genérico, la capacidad de declarar un espacio de nombres genérico sería extremadamente útil. Desafortunadamente, .Net (o al menos C #) no es compatible con la idea de espacios de nombres genéricos. Entonces, para lograr el mismo objetivo, podemos usar clases genéricas para cumplir el mismo objetivo. Tome las siguientes clases de ejemplo relacionadas con una entidad lógica:
Podemos simplificar las firmas de estas clases usando un espacio de nombres genérico (implementado a través de clases anidadas):
Luego, mediante el uso de clases parciales como sugirió Erik van Brakel en un comentario anterior, puede separar las clases en archivos anidados separados. Recomiendo usar una extensión de Visual Studio como NestIn para admitir el anidamiento de archivos de clase parciales. Esto permite que los archivos de clase del "espacio de nombres" también se utilicen para organizar los archivos de clase anidados en una carpeta similar.
Por ejemplo:
Entity.cs
Entity.BaseDataObject.cs
Entity.BaseDataObjectList.cs
Entity.IBaseBusiness.cs
Entity.IBaseDataAccess.cs
Los archivos en el explorador de soluciones de Visual Studio se organizarían así:
E implementaría el espacio de nombres genérico como el siguiente:
User.cs
User.DataObject.cs
User.DataObjectList.cs
User.IBusiness.cs
User.IDataAccess.cs
Y los archivos se organizarían en el explorador de soluciones de la siguiente manera:
Lo anterior es un ejemplo simple del uso de una clase externa como espacio de nombres genérico. He creado "espacios de nombres genéricos" que contienen 9 o más parámetros de tipo en el pasado. Tener que mantener esos parámetros de tipo sincronizados en los nueve tipos que todos necesitaban para conocer los parámetros de tipo era tedioso, especialmente al agregar un nuevo parámetro. El uso de espacios de nombres genéricos hace que el código sea mucho más manejable y legible.
fuente
Si entiendo bien el artículo de Katheleen, ella propone usar una clase anidada para poder escribir SomeEntity.Collection en lugar de EntityCollection <SomeEntity>. En mi opinión, es una forma controvertida de ahorrarle algo de escritura. Estoy bastante seguro de que, en el mundo real, las colecciones de aplicaciones tendrán alguna diferencia en las implementaciones, por lo que deberá crear una clase separada de todos modos. Creo que usar el nombre de la clase para limitar el alcance de otra clase no es una buena idea. Contamina el intellisense y fortalece las dependencias entre clases. El uso de espacios de nombres es una forma estándar de controlar el alcance de las clases. Sin embargo, encuentro que el uso de clases anidadas como en el comentario de @hazzen es aceptable a menos que tenga toneladas de clases anidadas, lo cual es una señal de mal diseño.
fuente
A menudo uso clases anidadas para ocultar los detalles de la implementación. Un ejemplo de la respuesta de Eric Lippert aquí:
Este patrón se vuelve aún mejor con el uso de genéricos. Vea esta pregunta para ver dos ejemplos interesantes. Entonces termino escribiendo
en vez de
También puedo tener una lista genérica de
Equality<Person>
pero noEqualityComparer<Person, int>
donde como
no es posible. Ese es el beneficio de la clase anidada heredada de la clase principal.
Otro caso (de la misma naturaleza - implementación oculta) es cuando desea que los miembros de una clase (campos, propiedades, etc.) sean accesibles solo para una sola clase:
fuente
Otro uso aún no mencionado para las clases anidadas es la segregación de tipos genéricos. Por ejemplo, suponga que uno quiere tener algunas familias genéricas de clases estáticas que puedan tomar métodos con varios números de parámetros, junto con valores para algunos de esos parámetros, y generar delegados con menos parámetros. Por ejemplo, uno desea tener un método estático que pueda tomar an
Action<string, int, double>
y producir unString<string, int>
que llame a la acción proporcionada pasando 3.5 comodouble
; también se puede desear tener un método estático que pueda tomar anAction<string, int, double>
y producir anAction<string>
, pasando7
comoint
y5.3
comodouble
. Usando clases anidadas genéricas, uno puede hacer arreglos para que las invocaciones de métodos sean algo como:o, porque los últimos tipos en cada expresión se pueden inferir aunque los primeros no pueden:
El uso de tipos genéricos anidados permite saber qué delegados son aplicables a qué partes de la descripción general del tipo.
fuente
Las clases anidadas se pueden utilizar para las siguientes necesidades:
fuente
Como Nawfal mencionó la implementación del patrón Abstract Factory, ese código se puede extender para lograr el patrón Class Clusters que se basa en el patrón Abstract Factory.
fuente
Me gusta anidar excepciones que son exclusivas de una sola clase, es decir. los que nunca se tiran de ningún otro lugar.
Por ejemplo:
Esto ayuda a mantener los archivos de su proyecto ordenados y no llenos de un centenar de pequeñas clases de excepción.
fuente
Tenga en cuenta que deberá probar la clase anidada. Si es privado, no podrá probarlo de forma aislada.
Sin embargo, puede convertirlo en interno junto con el
InternalsVisibleTo
atributo . Sin embargo, esto sería lo mismo que hacer que un campo privado sea interno solo con fines de prueba, lo que considero una mala auto documentación.Por lo tanto, es posible que desee implementar solo clases anidadas privadas que involucren baja complejidad.
fuente
si para este caso:
fuente
Basándome en mi comprensión de este concepto, podríamos usar esta característica cuando las clases están relacionadas entre sí conceptualmente. Quiero decir que algunos de ellos son un elemento completo en nuestro negocio, como entidades que existen en el mundo DDD que ayudan a un objeto raíz agregado a completar su lógica empresarial.
Para aclarar, voy a mostrar esto a través de un ejemplo:
Imagine que tenemos dos clases como Order y OrderItem. En la clase de pedido, vamos a administrar todos los artículos de pedido y en el artículo de pedido tenemos datos sobre un solo pedido para aclarar, puede ver las siguientes clases:
fuente