c# - solos - spiral knights se cierra solo




¿Se eliminan los objetos IDisponibles si el programa se cierra inesperadamente? (4)

Además de la respuesta de Patrick Hofman y Alexei, la limpieza puede no realizarse incluso si la aplicación finaliza correctamente.

Como probablemente sepa, no se llama al método Dispose cuando el recolector de basura recopila el objeto que implementa IDisposable interfaz IDisposable . Pero el GC llamará al método Finalize , también conocido como finalizador. En ella debes escribir tu lógica de limpieza usando el patrón de desecho . Y sí, .Net Framework intentará ejecutar todos los finalizadores, pero no hay garantía de que alguna vez se ejecuten.

Como ejemplo, el siguiente programa tiene el finalizador de ejecución muy larga. Por lo tanto, .Net terminará el proceso y nunca verá el mensaje.

class FinalizableObject
{
    ~FinalizableObject()
    {
        Thread.Sleep(50000);
        Console.WriteLine("Finalized");
    }
}

class Program
{
    static void Main(string[] args)
    {
        new FinalizableObject();
    }
}

Esto puede deberse a cualquier operación de larga duración, como liberar un identificador de red u otra cosa que requiera mucho tiempo.

Por lo tanto, nunca debe confiar en finalizadores y objetos desechables. Pero todos los controladores abiertos para los objetos del núcleo se cerrarán automáticamente, por lo que no debe preocuparse por ellos.

Le recomendaré que lea algunos artículos interesantes sobre los finalizadores y el GC además de las respuestas:

  1. Todos piensan en la recolección de basura de manera incorrecta (Raymond Chen)
  2. Cuando todo lo que sabes está mal, primera parte (Eric Lippert)
  3. Cuando todo lo que sabes está mal, segunda parte (Eric Lippert)
  4. Terminando un Proceso (MSDN)

¿Qué sucede si el programa sale de forma inesperada (ya sea por excepción o el proceso se termina)? ¿Hay situaciones como esta (o de otra manera) donde el programa terminará, pero los objetos IDisposable no se eliminarán correctamente?

La razón por la que pregunto es porque estoy escribiendo un código que se comunicará con un periférico, y quiero asegurarme de que no haya ninguna posibilidad de que quede en mal estado.


IDisposable es solo una interfaz. No hay absolutamente nada especial en la forma en que se manejan. Cuando llama a Dispose en un IDisposible (explícitamente o mediante un bloque de uso), llama al contenido de su método de Dispose. Obtiene la basura recogida como cualquier otro objeto.

El propósito de la interfaz es permitir que un implementador defina la limpieza de un tipo que puede tener recursos administrados o no administrados que deben limpiarse explícitamente.

Si todos estos recursos están administrados, la recolección de basura puede ser suficiente y las implementaciones pueden ser solo para optimización.

Si no están administrados o tienen alguna conexión con recursos no administrados, la recolección de basura probablemente no sea suficiente. Esta es la razón por la que la implementación completa recomendada de IDisposable implica el manejo tanto de la eliminación explícita como de la eliminación en tiempo de ejecución (a través de un finalizador).

El proceso no se cerrará y no se garantiza que los finalizadores se ejecuten ... por lo que debe esperar que la destrucción del proceso sea suficiente por sí misma.


Si el programa se cierra de forma inesperada (por ejemplo, cancela el proceso), no hay absolutamente ninguna garantía de que se IDisposable.Dispose método IDisposable.Dispose . Será mejor que no confíes en él para tales eventos. El código de Dispose debe llamarse manualmente por su código, no es algo que el CLR llamará automáticamente por usted.


Si la causa es una excepción y se lanza desde un bloque que using o un bloque de try catch finally , se eliminará como se debe. Si no es atrapado por un bloque que using , no se elimina automáticamente (como no lo hace cuando la aplicación se cierra correctamente).

Una muestra:

IDisposable d1 = new X();

using (IDisposable d2 = new X())
{
    throw new NotImplementedException();
}

d1.Dispose();

d1 no está dispuesto, d2 general es. Algunos tipos de excepciones pueden evitar el manejo del using bloques y también algunos bloqueos de programas. Si la causa es un fallo de alimentación o un fallo del sistema, no hay nada que pueda hacer, por supuesto.





terminate