¿Por qué usar clases parciales?

72

En mi opinión, la partialpalabra clave no hace más que permitir que una clase se divida entre varios archivos de origen. ¿Hay alguna razón para hacer esto que no sea para la organización del código? Lo he visto usado para eso en las clases de IU generadas.

Parece una mala razón para crear una palabra clave completa. Si una clase es lo suficientemente grande como para requerir múltiples archivos, probablemente esté haciendo demasiado. Pensé que tal vez podría usarlo para definir parcialmente una clase para que otro programador la complete, pero sería mejor hacer una clase abstracta.

Michael K
fuente
10
Tampoco es realmente una "palabra clave completa". Es una palabra clave contextual . partialsolo significa algo cuando viene antes class. Puede usarlo como nombre de identificación en otras partes del código, etc.
Dean Harding
44
Si los usa, y no es para el código generado, lo odio. No a usted personalmente, sino a usted en general. Odio buscar código a través de clases parciales.
Steven Evers
3
No es difícil "buscar código", todos los métodos de clase aún aparecen en el menú desplegable en VS, independientemente de la parte del parcial que esté viendo. Otros códigos de navegación también funcionan bien (ya sea una navegación "inteligente" estilo R # o un buen viejo shift-ctrl-f
Steve
2
Es un malentendido que las clases parciales tengan que estar en archivos separados.
Bart

Respuestas:

110

Es muy útil en todos los escenarios en los que una herramienta personalizada genera una parte de la clase porque le permite agregar lógica personalizada al código generado sin heredar la clase generada. Por cierto. También hay métodos parciales por la misma razón.

No se trata solo de la interfaz de usuario, sino también de otras tecnologías como Linq-To-Sql o Entity Framework que lo utilizan bastante.

Ladislav Mrnka
fuente
44
Además, le permite mantener su código bajo control de versión mientras deja el código generado fuera del control de versión.
Frank Shearar
3
Buen punto, nunca he pensado en eso. Sin embargo, solo lo he visto abusado en la práctica. Una forma para que los programadores (pésimos) mantengan manejable el tamaño del archivo.
Martin Wickman el
1
Los mejores ejemplos que he usado son: a) para contextos de datos de Linq a SQL donde desea ampliar las clases; b) extender las clases pasadas de los servicios web. En ningún caso es un abuso ni es un medio para mantener manejables los tamaños de archivo ... Sería radicalmente infeliz verlo usado de esa manera (y tomaría medidas ...)
Murph
3
Las clases de WinForm lo usan para ocultar todos los controles de creación de código del diseñador (especialmente importante porque al diseñador le gusta reordenar aleatoriamente todo el código que crea, lo que resulta en grandes problemas cuando se difunde / culpa), y si está trabajando con XML, la herramienta XSD puede cree clases parciales a partir del archivo de esquema nuevamente, lo que le permitirá separar su código del orden generado automáticamente.
Dan Neely
2
@MartinWickman no necesariamente pésimo. Es un buen punto de partida para refactorizar objetos de Dios en código heredado. Intente aclarar el panorama dividiendo las clases grandes en archivos separados primero. (Sé que tu comentario es muy antiguo)
Konrad Morawski
26

Como usted dice, a menudo se usa para separar el código generado. A menudo no tiene nada que ver con el tamaño de las clases / archivos.

El beneficio de separar el código generado es uno de estilo. El código generado puede ser bastante feo e ilegible y fallaría en muchos estándares de codificación (y comprobaciones de StyleCop), pero está bien, nadie tiene que leerlo o mantenerlo directamente. Entonces, si lo "oculta" en otro archivo, puede enfocarse en asegurarse de que el resto de la clase esté a la altura, pase las comprobaciones de StyleCop, etc.

Otra área donde la he usado es donde una clase implementa múltiples interfaces, puede ser bastante agradable separar la implementación en archivos separados, aunque esto es más una cuestión de preferencia personal, nunca he visto que requieran estándares de codificación ( o prevenir) esto.

Steve
fuente
9
Nunca pensé en usar parciales de clase para separar implementaciones de interfaz, es una excelente idea.
Mark Booth
Se trata de mucho más que estilo. Los desarrolladores de un generador de código tendrían que saltar a través de aros para permitirle editar el código en un archivo administrado por el generador, e incluso entonces sería problemático. El beneficio # 1, para mí, es darle un lugar para escribir código que el generador no podrá tocar. Este es un beneficio bastante tangible.
Daniel
19

Hace un par de semanas, uno de los desarrolladores en los que trabajo tuvo un uso bastante bueno para ellos en la refactorización de grandes clases de Dios que se han salido de control y tienen muchos métodos públicos: separando las funciones lógicas de cada bit de la clase en clases parciales separadas puede separar físicamente la clase en las unidades más atómicas que deberían ser las clases sin romper ninguna funcionalidad existente, lo que le permite ver qué es común y qué no. Con esto como una primera etapa, puede dividir más fácilmente los parciales en sus propias clases independientes e implementarlos en toda la base de código. Pensé que era una buena idea.

Sin embargo, en general creo que solo deberían usarse para aumentar las clases generadas por la máquina al escribir código nuevo.


fuente
1
Puedo ver cómo eso podría ser útil. Si eso es justificación para que esté en el idioma o no ... No lo sé. Sin embargo, el código generado por máquina es otra historia.
Michael K
2
Sí, no es una justificación para que esté en el idioma, pero es una forma interesante de usarlos.
18

Puedo pensar en algunos escenarios útiles en los que los parciales tienen sentido, la mayoría de ellos los estoy usando en mis proyectos:

  • Para separar el código generado por Tool / IDE / Designer del código que está manteniendo. Un buen ejemplo es el Form.Designer.csarchivo que contiene el código generado por el diseñador para las aplicaciones de formularios de Windows. Muchos otros formatos .NET también tienen código generado por herramientas, que puede regenerarse potencialmente cuando construye su proyecto, y por lo tanto, todos sus cambios personalizados se eliminarán. La separación lo ayudará a mantener su código y los cambios a salvo de tales modificaciones automáticas.

  • Cuando implementa múltiples interfaces con mucho código en la implementación. Yo tiendo a usar un archivo parcial por separado para cada interfaz, dándole el nombre de esta manera: {Class}.{Interface}.cs. Es fácil para mí ver en el IDE qué interfaces {Class}está implementando y cómo.

  • Cuando la clase debe contener una o más clases anidadas , especialmente con suficiente código para colocarlas en un archivo separado. Me apegaría al patrón anterior y usaría la {Class}.{NestedClass}.csconvención de nomenclatura para cada clase anidada. Práctica similar ya se menciona en la respuesta de Virtlink .

  • Cuando escribo staticclases que contendrán métodos de extensión . A menudo será el caso proporcionar la misma lógica de método de extensión a clases o interfaces similares, como por ejemplo Reverseen colecciones genéricas y no genéricas. Pondría todos los métodos de extensión para una sola clase o interfaz en un parcial separado de la clase estática. Por ejemplo, tendría todos los métodos de extensión para la IListinterfaz en un lugar, y los mismos métodos para IList<T>otro archivo. Otro enfoque sería colocar el mismo método (todas sus sobrecargas) en el mismo parcial, con todas las clases posibles para el thisparámetro, como tener todas lasReverseimplementaciones en un archivo. Depende de cuál justificaría mejor la separación en términos de volumen de código, o algunas convenciones internas a las que usted o su organización podrían estar apegándose.

  • No uso esto, pero he visto a algunas personas de C / C ++ que les gusta el enfoque que describiré aquí: crear un parcial para la clase solo con métodos parciales . Esto se parece a la forma C / C ++ de definir interfaces y separar la declaración del método de la implementación.

  • Separación por preocupaciones puramente lógicas . Si trabaja con una clase grande que combina más de un conjunto lógico de operaciones en sí mismo, entonces podría separar cada código lógicamente relacionado en un parcial separado. Por lo general, la existencia de tales clases está en contra del principio de separación de preocupaciones , pero a menudo se observa el caso de la vida real, especialmente para las bases de código más antiguas. El usuario Steve Evers los ha mencionado en su respuesta a esta pregunta , refiriéndose a ellos por el nombre de objetos de dios. Yo personalmente usaría el enfoque de clases parciales para dividir el código antes de que tenga lugar una refactorización de archivos tan grandes, para facilitar mi trabajo y hacer que la refactorización sea más transparente. Esto también reducirá los conflictos que potencialmente causaré cuando estén involucrados sistemas de versiones como SVN.

Ivaylo Slavov
fuente
14

No lo he visto mencionado por nadie: lo uso partialpara poner clases anidadas en sus propios archivos.

Todos mis archivos de código contienen solo una clase, estructura, interfaz o enumeración. Hace que sea mucho más fácil encontrar la definición de un objeto cuando los nombres de los archivos muestran el nombre de lo que está buscando. Y dado que Visual Studio intenta hacer coincidir las carpetas del proyecto con los espacios de nombres, los nombres de los archivos deben coincidir con las clases.

Esto también significa que una clase NestedClassanidada dentro MyClasstendrá su propio archivo en mis proyectos: MyClass.NestedClass.cs.

partial class MyClass
{
    private class NestedClass
    {
        // ...
    }
}
Daniel AA Pelsmaeker
fuente
1
Me pregunto por qué uno rechazaría esta respuesta. La práctica mencionada no es un anti-patrón, ni causaría ningún problema que conozca.
Ivaylo Slavov
1
Esto también resuelve el problema de mantener pequeños los archivos de clase (en términos de líneas de código) mientras se permite la encapsulación adecuada del código que pertenece a una clase interna.
redcalx
10

Con la excepción del uso de código generado, solo los he visto usar en un esfuerzo por encubrir objetos de Dios . Intentar comprender una nueva base de código o navegar a través de múltiples archivos fuente, que son el mismo objeto, es muy molesto.

Entonces, cuando preguntas Why use partial classes?, respondo: a menos que estés usando el código generado, no lo hagas.

Steven Evers
fuente
+1. Es la primera vez que veo que este tipo de objetos reciben un nombre (objetos de Dios) e incluso es oficial. Nunca es demasiado tarde para aprender algo nuevo.
Ivaylo Slavov
6

La organización del código es la única razón, pero es más profunda de lo que parece a primera vista. Si tiene clases parciales donde se generan partes, puede fácilmente:

  • Regenere el código sin tener que detectar cambios manuales en las clases en las que escribe (para no sobrescribir esas partes).
  • Excluya las clases parciales generadas de la cobertura de prueba, control de fuente, métricas, etc.
  • Use el código generado sin obligarlo a basar su estrategia de herencia en torno a él (aún puede heredar de otras clases).
Deckard
fuente
1

También hay algunos lugares donde las clases generadas / implícitas se declaran parciales, por lo que si el desarrollador necesita extenderlas, tienen acceso completo sin tener que preocuparse por heredar y anular todo el lugar. Observe las clases generadas en el área temporal asp.net después de ejecutar un sitio de formularios web por primera vez en IIS si desea obtener algunos ejemplos.

Cuenta
fuente
1

Puedo pensar en un uso sucio para ellos.

Suponga que tiene algunas clases que necesitan una funcionalidad común, pero no desea inyectar esa funcionalidad en la cadena de herencia que se encuentra sobre ellas. O bien, tiene un conjunto de clases que utilizan una clase auxiliar común.

Básicamente, desea hacer herencia múltiple, pero C # no es similar. Entonces, lo que haces es usar parcial para crear lo que es esencialmente un #include en C / C ++;

Ponga toda la funcionalidad en una clase, o use la clase auxiliar. Luego copie el ayudante X veces y cámbiele el nombre a la clase parcial A, B, C. y poner parcial en sus clases A, B, C.

Descargo de responsabilidad: Sí, esto es malo. No lo hagas nunca, especialmente si enfadará a otras personas contigo.

marca
fuente
Mixins Esto podría combinarse con T4 para evitar la copia manual ...
Peter Taylor
Como se señaló, esto se parece mucho a las mixinas. Sin embargo, se está acercando a un concepto conocido como "rasgos" y manejarán con seguridad lo que está tratando de lograr. Tengo una descripción independiente del idioma en publius-ovidius.livejournal.com/314737.html . Busqué una implementación limpia para C #, pero no la he visto.
Ovidio