c# class-design nested-class

c# - Clases anidadas "públicas" o no



class-design nested-class (5)

Es posible que desee comprobar lo que Microsoft tiene que decir sobre el tema. Básicamente es una cuestión de estilo, diría yo.

Supongamos que tengo una ''Aplicación'' de clase. Para inicializarse, requiere ciertas configuraciones en el constructor. Supongamos también que la cantidad de configuraciones es tan alta que resulta convincente ubicarlas en una clase propia.

Compare las siguientes dos implementaciones de este escenario.

Implementación 1:

class Application { Application(ApplicationSettings settings) { //Do initialisation here } } class ApplicationSettings { //Settings related methods and properties here }

Implementación 2:

class Application { Application(Application.Settings settings) { //Do initialisation here } class Settings { //Settings related methods and properties here } }

Para mí, el segundo enfoque es mucho más preferible. Es más legible porque enfatiza fuertemente la relación entre las dos clases. Cuando escribo código para instanciar la clase Application en cualquier lugar, el segundo enfoque se verá más bonito.

Ahora imagina que la clase de Configuración a su vez tenía una clase similar "relacionada" y esa clase a su vez también lo hizo. Vaya solo a tres niveles y el nombre de la clase se salga de control en el caso "no anidado". Si anida, sin embargo, las cosas siguen siendo elegantes.

A pesar de lo anterior, he leído personas que dicen en StackOverflow que las clases anidadas están justificadas solo si no son visibles para el mundo exterior; eso es si se usan solo para la implementación interna de la clase contenedora. La objeción comúnmente citada es hinchar el tamaño del archivo fuente de la clase que contiene, pero las clases parciales son la solución perfecta para ese problema.

Mi pregunta es, ¿por qué tenemos cuidado con el uso "públicamente expuesto" de las clases anidadas? ¿Hay algún otro argumento en contra de tal uso?


Puede usar espacios de nombres para relacionar cosas que están ... relacionadas.

Por ejemplo:

namespace Diner { public class Sandwich { public Sandwich(Filling filling) { } } public class Filling { } }

La ventaja de esto sobre el uso de clases como si fueran espacios de nombres es que opcionalmente puede usar el using en el lado de la llamada para abreviar cosas:

using Diner; ... var sandwich = new Sandwich(new Filling());

Si utiliza la clase Sandwich como si fuera un espacio de nombre para Filling , debe utilizar el nombre completo Sandwich.Filling . Filling para referirse a Filling .

¿Y cómo vas a dormir en la noche sabiendo eso?


Creo que está bien. Este es básicamente el patrón del constructor, y el uso de clases anidadas funciona bastante bien. También permite que el constructor acceda a miembros privados de la clase externa, lo que puede ser muy útil. Por ejemplo, puede tener un método de compilación en el constructor que llame a un constructor privado en la clase externa que toma una instancia del constructor:

public class Outer { private Outer(Builder builder) { // Copy stuff } public class Builder { public Outer Build() { return new Outer(this); } } }

Eso asegura que la única forma de construir una instancia de la clase externa es a través del constructor.

Utilizo un patrón muy parecido a este en mi puerto C # de Protocol Buffers.


Otro ejemplo práctico que tengo para un uso válido de las clases públicas anidadas está en el patrón MVC cuando uso un modelo de vista con una propiedad IEnumerable. por ejemplo:

public class OrderViewModel { public int OrderId{ get; set; } public IEnumerable<Product> Products{ get; set; } public class Product { public string ProductName{ get; set; } public decimal ProductPrice{ get; set; } } }

Lo uso porque no quiero que la clase de Product sea ​​reutilizada en el exterior porque está personalizada solo para ese modelo de vista específico que lo contiene. Pero no puedo hacerlo privado porque la propiedad de los Productos es pública.


Principalmente uso clases anidadas para ajustar el acceso a la clase anidada y / o contenedor.

Una cosa para recordar es que una definición de clase anidada es básicamente un miembro de la clase, y tendrá acceso a todas las variables privadas del contenedor.

También puede usar esto para controlar el uso de una clase específica.

Ejemplo:

public abstract class Outer { protected class Inner { } }

Ahora, en este caso, el usuario (de su clase) solo puede acceder a la clase interna, si implementa Outer.