propiedades esperaba español descriptores declarar como clases atributos anidadas acceso c# nested-class

c# - esperaba - ¿Cuáles son las razones por las que uno querría usar clases anidadas?



propiedades get c# (14)

Las "clases anidadas privadas" pueden ser bastante útiles

Note lo privado en esa oración. No se recomiendan los tipos anidados públicos.

Y como la mayoría de las respuestas, tenga en cuenta: cada clase es un pequeño proyecto de software por sí solo. A veces se hace deseable dar de alta las clases de ayuda. Pero no es algo por lo que luchar, todavía no quieres que las clases sean demasiado grandes o demasiado complejas.

Esta pregunta ya tiene una respuesta aquí:

En esta respuesta de stackoverflow, un comentarista mencionó que las " clases anidadas privadas" pueden ser bastante útiles, así que leí sobre ellas en artículos como este, que tienden a explicar cómo funcionan técnicamente las clases anidadas, pero no por qué las usaría.

Supongo que usaría clases privadas anidadas para pequeñas clases de ayudantes que pertenecen a una clase más grande, pero a menudo necesitaré una clase de ayuda de otra clase y, por lo tanto, tendría que hacer un esfuerzo adicional para (1) anular la clase anidada -nested o (2) hacerlo público y luego acceder a él con el prefijo de clase externa, lo que parece ser un trabajo extra sin ningún valor agregado por tener la clase anidada en primer lugar. Por lo tanto, en general , no veo un caso de uso para las clases anidadas , excepto tal vez para mantener las clases un poco más organizadas en grupos, pero eso también va en contra de la claridad de una clase por archivo que he venido a disfrutar. .

¿De qué manera utiliza las clases anidadas para que su código sea más manejable, legible y eficiente?


Clases privadas de ayuda es un buen ejemplo.

Por ejemplo, objetos de estado para subprocesos de fondo. No hay ninguna razón convincente para exponer esos tipos. Definirlos como tipos anidados privados parece una forma bastante limpia de manejar el caso.


Creo que otros han cubierto bien los casos de uso para clases anidadas públicas y privadas.

Un punto que no he visto fue una respuesta a su preocupación sobre una clase por archivo . Puede resolver esto haciendo que la clase externa sea parcial y mueva la definición de la clase interna a un archivo separado.

OuterClass.cs:

namespace MyNameSpace { public partial class OuterClass { // main class members here // can use inner class } }

OuterClass.Inner.cs:

namespace MyNameSpace { public partial class OuterClass { private class Inner { // inner class members here } } }

Incluso podría hacer uso del anidamiento de elementos de Visual Studio para hacer que OuterClass.Inner.cs sea un ''hijo'' de OuterClass.cs, para evitar saturar su explorador de soluciones.


Devolver una interfaz a la persona que llama cuya implementación desea ocultar.

public class Outer { private class Inner : IEnumerable<Foo> { /* Presumably this class contains some functionality which Outer needs * to access, but which shouldn''t be visible to callers */ } public IEnumerable<Foo> GetFoos() { return new Inner(); } }


Generalmente lo hago cuando necesito una combinación de SRP (Responsabilidad única principal) en ciertas situaciones.

"Bueno, si SRP es su objetivo, ¿por qué no los divide en clases diferentes? " Hará esto el 80% del tiempo, pero ¿qué pasa con las situaciones en que las clases que crea son inútiles para el mundo exterior? No desea clases que solo utilizará para saturar la API de su ensamblaje.

"Bueno, ¿no es eso para lo que es internal ?" Por supuesto. Por alrededor del 80% de estos casos. Pero ¿qué pasa con las clases internas que deben acceder o modificar el estado de las clases públicas? Por ejemplo, ¿esa clase que se dividió en una o más clases internas para satisfacer su racha de SRP? Tendría que marcar todos los métodos y propiedades para que usen estas clases internal como internal también.

"¿Qué está mal con eso?" Nada. Por alrededor del 80% de estos casos. Por supuesto, ahora está saturando la interfaz interna de sus clases con métodos / propiedades que solo sirven para las clases que creó anteriormente. Y ahora tiene que preocuparse de que otras personas de su equipo escriban un código interno que no estropeará su estado utilizando esos métodos de una forma que no esperaba.

Las clases internas consiguen modificar el estado de cualquier instancia del tipo en el que están definidas. Por lo tanto, sin agregar miembros a la definición de su tipo, sus clases internas pueden trabajar según sea necesario. Lo que, en aproximadamente 14 casos en 100, será su mejor apuesta para mantener sus tipos limpios, su código confiable / mantenible y sus responsabilidades singulares.


Has respondido tu propia pregunta. Use clases anidadas cuando necesite una clase auxiliar que no tenga sentido fuera de la clase; particularmente cuando la clase anidada puede hacer uso de los detalles de implementación privada de la clase externa.

Su argumento de que las clases anidadas son inútiles también es un argumento de que los métodos privados son inútiles: un método privado podría ser útil fuera de la clase y, por lo tanto, tendría que hacerlo interno. Un método interno podría ser útil fuera del ensamblaje y, por lo tanto, lo haría público. Por lo tanto todos los métodos deben ser públicos. Si crees que es un mal argumento, ¿qué tiene de diferente hacer que el mismo argumento para las clases en lugar de los métodos?

Hago clases anidadas todo el tiempo porque con frecuencia estoy en la posición necesaria para encapsular la funcionalidad en un ayudante que no tiene sentido fuera de la clase y puedo usar los detalles de implementación privada de la clase externa. Por ejemplo, escribo compiladores. Recientemente escribí una clase de analizador semántico que hace análisis semánticos de árboles de análisis. Una de sus clases anidadas es LocalScopeBuilder. ¿Bajo qué circunstancias necesitaría construir un ámbito local cuando no estoy analizando la semántica de un árbol de análisis? Nunca. Esa clase es completamente un detalle de implementación del analizador semántico. Planeo agregar más clases anidadas con nombres como NullableArithmeticAnalyzer y OverloadResolutionAnalyzer que tampoco son útiles fuera de la clase, pero quiero resumir las reglas del lenguaje en esas clases específicas.

Las personas también usan clases anidadas para construir cosas como iteradores o comparadores, cosas que no tienen sentido fuera de la clase y se exponen a través de una interfaz conocida.

Un patrón que uso con bastante frecuencia es tener clases anidadas privadas que extienden su clase externa:

abstract public class BankAccount { private BankAccount() { } // Now no one else can extend BankAccount because a derived class // must be able to call a constructor, but all the constructors are // private! private sealed class ChequingAccount : BankAccount { ... } public static BankAccount MakeChequingAccount() { return new ChequingAccount(); } private sealed class SavingsAccount : BankAccount { ... }

y así. Las clases anidadas funcionan muy bien con el patrón de fábrica. Aquí BankAccount es una fábrica para varios tipos de cuentas bancarias, todas las cuales pueden utilizar los detalles de implementación privada de BankAccount. Pero ningún tercero puede hacer su propio tipo EvilBankAccount que amplíe BankAccount.


He encontrado algunos casos en los que han sido bastante útiles:

  1. Gestión de un estado privado complejo, como un InterpolationTriangle utilizado por una clase de Interpolator. El usuario del Interpolator no necesita saber que se implementó utilizando la triangulación de Delauney y ciertamente no necesita saber sobre los triángulos, por lo que la estructura de datos es una clase anidada privada.

  2. Como han mencionado otros, puede exponer los datos utilizados por la clase con una interfaz sin revelar la implementación completa de una clase. Las clases anidadas también pueden acceder al estado privado de la clase externa, lo que le permite escribir código estrechamente acoplado sin exponer ese acoplamiento estrecho públicamente (o incluso internamente al resto del ensamblaje).

  3. Me he encontrado con algunos casos en los que un marco espera que una clase se derive de alguna clase base (como DependencyObject en WPF), pero desea que su clase herede de una base diferente. Es posible interoperar con el marco utilizando una clase anidada privada que desciende de la clase base del marco. Debido a que la clase anidada puede acceder al estado privado (solo se le pasa el ''esto'' de los padres cuando lo crea), básicamente puede usar esto para implementar la herencia múltiple de un hombre pobre a través de la composición.


La pregunta está etiquetada como C #, por lo que no estoy seguro de que sea de su interés, pero en COM puede usar clases internas para implementar interfaces cuando una clase C ++ implementa múltiples interfaces COM ... esencialmente, la usa para composición en lugar de herencia múltiple.

Además, en MFC y tal vez en otras tecnologías, es posible que necesite que su control / diálogo tenga una clase de destino final, lo que no tiene mucho sentido más que como una clase anidada.


Las clases anidadas privadas anónimas son esenciales para los manejadores de eventos en la GUI.

Si alguna clase no forma parte de la API, otra clase exporta, debe hacerse privada. De lo contrario, estás exponiendo más de lo que pretendes. El "error del millón de dólares" fue un ejemplo de esto. La mayoría de los programadores son demasiado flojos sobre esto.

Peter


Los uso cuando dos valores enlazados (como en una tabla hash) no son suficientes internamente, pero sí lo son externamente. Luego creo una clase anidada con las propiedades que necesito almacenar, y expongo solo algunas de ellas a través de métodos.

Creo que esto tiene sentido, porque si nadie más lo va a usar, ¿por qué crear una clase externa para eso? Simplemente no tiene sentido.

En cuanto a una clase por archivo, puede crear clases parciales con la palabra clave partial , que es lo que normalmente hago.


Si es necesario que un objeto devuelva información abstracta sobre su estado, una clase anidada privada puede ser adecuada. Por ejemplo, si un Fnord admite los métodos "guardar contexto" y "restaurar contexto", puede ser útil que la función "guardar contexto" devuelva un objeto de tipo Fnord.SavedContext. Las reglas de acceso de tipo no son siempre las más útiles; por ejemplo, parece difícil permitir que Fnord acceda a las propiedades y los métodos de un Fnord.SavedContext sin hacer que dichas propiedades y métodos sean visibles para personas externas. Por otro lado, uno podría tener Fnord.CreateSaveContext simplemente crear un Nuevo Fnord.SaveContext con el Fnord como parámetro (ya que Fnord.SaveContext puede acceder a las partes internas de Fnord), y Fnord.LoadContextFrom () puede llamar a Fnord.SaveContext.Restacuent ().


Son realmente agradables para, por ejemplo, una implementación del patrón singleton.

Tengo un par de lugares donde los uso para "agregar" valor, también. Tengo un cuadro combinado de selección múltiple donde mi clase interna almacena el estado de la casilla de verificación y el elemento de datos también. no es necesario que el mundo conozca / use esta clase interna.


Un ejemplo convincente que he encontrado recientemente es la clase Node de muchas estructuras de datos. Un Quadtree , por ejemplo, necesita saber cómo almacena los datos en sus nodos, pero a ninguna otra parte de su código debería importarle.


Un patrón muy común donde se usa esta técnica es en escenarios donde una clase devuelve una interfaz o un tipo de clase base de una de sus propiedades o métodos, pero el tipo concreto es una clase anidada privada. Considere el siguiente ejemplo.

public class MyCollection : IEnumerable { public IEnumerator GetEnumerator() { return new MyEnumerator(); } private class MyEnumerator { } }