tipos pattern net destructors crear constructores clases c# .net struct destructor finalizer

net - disposable c# pattern



¿Por qué las estructuras no pueden tener destructores? (4)

¿Cuál es la mejor respuesta en la entrevista en la pregunta que crees?

Creo que no encontré una copia de esto aquí, si hay una, por favor vincúlala.


De Jon Jagger :

"Una estructura no puede tener un destructor. Un destructor es solo una anulación del objeto. object.Finalize disfrazado, y las estructuras, al ser tipos de valor, no están sujetas a recolección de basura".


Otra forma de ver esto, en lugar de simplemente citar la especificación que dice que las estructuras no pueden / no tienen destructores, considere qué pasaría si se cambiara la especificación para que lo hicieran o, mejor dicho, hagamos la pregunta: puede Adivinamos ¿por qué los diseñadores de idiomas decidieron no permitir que las estructuras tuvieran "destructores" en primer lugar?

(No se obsesione con la palabra ''destructor'' aquí; básicamente estamos hablando de un método mágico en estructuras que se llama automáticamente cuando la variable está fuera de alcance. En otras palabras, una característica de lenguaje análoga a los destructores de C ++. )

Lo primero que hay que darse cuenta es que no nos importa liberar la memoria. Ya sea que el objeto esté en la pila o en el montón (por ejemplo, una estructura en una clase), la memoria se cuidará de una forma u otra, tarde o temprano; ya sea por ser extraído de la pila o por ser recogido. La razón real para tener algo que es como un destructor en primer lugar es la administración de recursos externos , como los manejadores de archivos, los manejadores de ventanas u otras cosas que requieren un manejo especial para limpiarlos que el CLR mismo no conoce.

Ahora se supone que permites que una estructura tenga un destructor que puede hacer esta limpieza. Multa. Hasta que te das cuenta de que cuando las estructuras se pasan como parámetros, se pasan por valor: se copian. Ahora tienes dos estructuras con los mismos campos internos, y ambos intentarán limpiar el mismo objeto. Uno sucederá primero, y así el código que usa el otro luego comenzará a fallar misteriosamente ... y luego su propia limpieza fallará (¡con suerte! - en el peor de los casos, podría tener éxito en limpiar algún otro recurso al azar; esto puede sucede en situaciones en las que los valores de los identificadores se reutilizan, por ejemplo

Podría concebir un caso especial para las estructuras que son parámetros para que sus "destructores" no se ejecuten (pero tenga cuidado, ahora debe recordar que al llamar a una función, siempre es el externo el que "posee" el recurso real). - ahora algunas estructuras son sutilmente diferentes a otras ...) - pero aún tiene este problema con las variables de estructura regulares, donde una puede asignarse a otra, haciendo una copia.

Quizás pueda evitar esto agregando un mecanismo especial a las operaciones de asignación que de alguna manera permita que la nueva estructura negocie la propiedad del recurso subyacente con su nueva copia, tal vez la compartan o transfieran la propiedad directamente de la antigua a la nueva, pero ahora usted Básicamente, nos hemos dirigido a C ++ - land, donde necesita copiar constructores, operadores de asignación y ha agregado un montón de sutilezas esperando para atrapar al programador novato que no lo sabe. Y tenga en cuenta que todo el objetivo de C # es evitar ese tipo de complejidad de estilo C ++ tanto como sea posible.

Y, solo para hacer las cosas un poco más confusas, como señala una de las otras respuestas, las estructuras no solo existen como objetos locales. Con los locales, el alcance es agradable y bien definido; pero las estructuras también pueden ser miembros de un objeto de clase. ¿Cuándo debería llamarse al ''destructor'' en ese caso? Claro, puedes hacerlo cuando se finalice la clase de contenedor; pero ahora tiene un mecanismo que se comporta de manera muy diferente dependiendo de dónde vive la estructura: si la estructura es local, se activa inmediatamente al final del alcance; si la estructura está dentro de una clase, se activa de manera perezosa ... Entonces, si realmente te importa asegurarte de que algún recurso en una de tus estructuras se limpie en un momento determinado, y si tu estructura podría terminar como miembro de un clase, probablemente necesitarías algo explícito como IDisposable / using () de todos modos para asegurarte de que tienes tus bases cubiertas.

Entonces, si bien no puedo decir que hablo por los diseñadores de idiomas, puedo hacer una buena suposición de que una razón por la que decidieron no incluir esa característica es porque sería una lata de gusanos, y querían que C # fuera razonablemente simple. .


Todos los objetos, excepto los arreglos y las cadenas, se almacenan en el montón de la misma manera: un encabezado que proporciona información sobre las propiedades "relacionadas con el objeto" (su tipo, si es utilizado por cualquier bloqueo de monitor activo, si tiene un no suprimido Finalize método, etc.), y sus datos (es decir, el contenido de todos los campos de instancia del tipo (públicos, privados y protegidos entremezclados, con campos de clase base que aparecen antes de los campos de tipo derivado). Debido a que cada objeto de montón tiene un encabezado, el sistema puede hacer referencia a cualquier objeto y saber qué es, y qué se supone que debe hacer con él el recolector de basura. Si el sistema tiene una lista de todos los objetos que se han creado y tiene un método Finalize , puede examinar todos los objetos de la lista, ver si su método de Finalize está suprimido, y actuar de forma apropiada.

Las estructuras se almacenan sin ningún encabezado; una estructura como Point con dos campos de enteros se almacena simplemente como dos enteros. Si bien es posible tener una ref a una estructura (tal cosa se crea cuando una estructura se pasa como un parámetro de ref ), el código que usa la ref debe saber a qué tipo de estructura apunta la ref , ya que ni la ref ni la estructura en sí misma contiene esa información. Además, los objetos del montón solo pueden ser creados por el recolector de basura, lo que garantizará que cualquier objeto que se cree siempre existirá hasta el próximo ciclo de GC. Por el contrario, el código de usuario puede crear y destruir estructuras por sí mismo (a menudo en la pila); Si el código crea una estructura junto con una ref , y pasa esa ref a una rutina llamada, no hay forma de que el código pueda destruir la estructura (o hacer nada, hasta el momento) hasta que la rutina llamada regrese, por lo que Se garantiza que la estructura existe al menos hasta que la rutina llamada salga. Por otro lado, una vez que la rutina llamada salga, la ref que se le otorgó debería presumirse como no válida, ya que el llamante tendría la libertad de destruir la estructura en cualquier momento posterior.


Los destructores, por definición, se utilizan para destruir instancias de clases y las estructuras son tipos de valor.

Ref: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

Por las propias palabras de Microsoft: "Destructors are used to destruct instances of classes." así que es un poco tonto preguntar "¿Por qué no puedes usar un destructor ( algo que no es una clase )?" ^^