Elegir entre clases y structs

Nota:

Este contenido se ha copiado con permiso de Pearson Education, Inc. de Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2ª edición. Esa edición se publicó en 2008 y el libro se ha revisado completamente en la tercera edición. Parte de la información de esta página puede estar obsoleta.

Una de las decisiones básicas de diseño a las que se enfrenta cada diseñador de marcos es si se debe diseñar un tipo como una clase (un tipo de referencia) o como una estructura (un tipo de valor). Una buena comprensión de las diferencias en el comportamiento de los tipos de referencia y los tipos de valor es fundamental para tomar esta elección.

La primera diferencia entre los tipos de referencia y los tipos de valor que consideraremos es que los tipos de referencia se asignan en el montón y la recolección de elementos no utilizados, mientras que los tipos de valor se asignan en la pila o en línea en que contienen tipos y se desasignan cuando la pila se desasigna o cuando su tipo contenedor se desasigna. Por lo tanto, las asignaciones y desasignaciones de tipos de valor son en general más baratas que las asignaciones y desasignaciones de tipos de referencia.

A continuación, las matrices de tipos de referencia se asignan fuera de línea, lo que significa que los elementos de matriz son simplemente referencias a instancias del tipo de referencia que residen en el montón. Las matrices de tipo de valor se asignan en línea, lo que significa que los elementos de matriz son las instancias reales del tipo de valor. Por lo tanto, las asignaciones y desasignaciones de tipos de valor son en general más baratas que las asignaciones y desasignaciones de tipos de referencia. Además, en la mayoría de los casos, las matrices de tipos de valor presentan una localidad de referencia mucho mejor.

La siguiente diferencia está relacionada con el uso de memoria. Los tipos de valor se boxean cuando se convierten a un tipo de referencia o a una de las interfaces que implementan. Se unboxean al convertir al tipo de valor. Dado que las casillas son objetos que se asignan en el montón y son recolección de elementos no utilizados, demasiado boxing y unboxing pueden tener un impacto negativo en el montón, el recolector de elementos no utilizados y, en última instancia, el rendimiento de la aplicación. En cambio, no se produce este tipo de boxeo a medida que se convierten los tipos de referencia. (Para obtener más información, consulte Conversión boxing y unboxing).

A continuación, las asignaciones de tipo de referencia copian la referencia, mientras que las asignaciones de tipo de valor copian todo el valor. Por lo tanto, las asignaciones de tipos de referencia grandes son más baratas que las asignaciones de tipos de valores grandes.

Por último, los tipos de referencia se pasan por referencia, mientras que los tipos de valor se pasan por valor. Los cambios en una instancia de un tipo de referencia afectan a todas las referencias que apuntan a la instancia. Las instancias de tipo de valor se copian cuando se pasan por valor. Cuando se cambia una instancia de un tipo de valor, por supuesto no afecta a ninguna de sus copias. Dado que el usuario no crea explícitamente las copias, pero se crean implícitamente cuando se pasan argumentos o se devuelven valores devueltos, los tipos de valor que se pueden cambiar pueden resultar confusos para muchos usuarios. Por lo tanto, los tipos de valor deben ser inmutables.

Como regla general, la mayoría de los tipos en un marco debe ser clases. Sin embargo, hay algunas situaciones en las que las características de un tipo de valor hacen que sea más adecuado usar estructuras.

✔️ CONSIDERE la posibilidad de definir una estructura en lugar de una clase si las instancias del tipo son pequeñas y normalmente de corta duración o se insertan normalmente en otros objetos.

❌ EVITE definir una estructura a menos que el tipo tenga todas las características siguientes:

  • Representa lógicamente un único valor, similar a los tipos primitivos (int, double, etc.).

  • Tiene un tamaño de instancia inferior a 16 bytes.

  • Es inmutable.

  • No será necesario que se boxee con frecuencia.

En todos los demás casos, debe definir los tipos como clases.

Portions © 2005, 2009 Microsoft Corporation. Todos los derechos reservados.

Material reimpreso con el consentimiento de Pearson Education, Inc. y extraído de Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition (Instrucciones de diseño de .NET Framework: convenciones, expresiones y patrones para bibliotecas .NET reutilizables, 2.ª edición), de Krzysztof Cwalina y Brad Abrams, publicado el 22 de octubre de 2008 por Addison-Wesley Professional como parte de la serie Microsoft Windows Development.

Vea también