2009-07-02 22 views
74

¿Cuál es la diferencia, si existe, entre un destructor y un método Finalize en una clase?En C# ¿cuál es la diferencia entre un destructor y un método Finalize en una clase?

Recientemente descubrí que Visual Studio 2008 considera un destructor sinónimo de un método Finalize, lo que significa que Visual Studio no le permitirá definir simultáneamente ambos métodos en una clase.

Por ejemplo, el siguiente fragmento de código:

class TestFinalize 
{ 
    ~TestFinalize() 
    { 
     Finalize(); 
    } 

    public bool Finalize() 
    { 
     return true; 
    } 
} 

da el siguiente error en la llamada para finalizar en el destructor:

The call is ambiguous between the following methods or properties: 'TestFinalize.~TestFinalize()' and 'TestFinalize.Finalize()'

Y si la llamada para finalizar se comenta, se da el siguiente error:

Type 'ManagementConcepts.Service.TestFinalize' already defines a member called 'Finalize' with the same parameter types

Respuesta

52

Un destructor en C# anula el método System.Object.Finalize. Usted tiene que usar la sintaxis del destructor para hacerlo. Anular manualmente Finalize le dará un mensaje de error.

Básicamente lo que está tratando de hacer con su declaración de método Finalize es hiding el método de la clase base. Hará que el compilador emita una advertencia que se puede silenciar utilizando el modificador new (si fuera a funcionar). Lo importante a destacar aquí es que usted no puede tanto override y declarar un miembro new con nombre idéntico al mismo tiempo, por lo que tener tanto un destructor y un método Finalize dará lugar a un error (pero puedo , aunque no recomendado, declare un método public new void Finalize() si no está declarando un destructor).

16

Found here: http://sanjaysainitech.blogspot.com/2007/06/difference-between-destructor-dispose.html

  1. Destructor

    They are special methods that contains clean up code for the object. You can not call them explicitly in your code as they are called implicitly by GC. In C# they have same name as the class name preceded by the ~ sign. Like-

    Class MyClass 
    { 
    
    ~MyClass() 
    { 
    ..... 
    } 
    } 
    

    In VB.NET, destructors are implemented by overriding the Finalize method of the System.Object class.

  2. Dispose

    These are just like any other methods in the class and can be called explicitly but they have a special purpose of cleaning up the object. In the dispose method we write clean up code for the object. It is important that we freed up all the unmanaged recources in the dispose method like database connection, files etc. The class implementing dispose method should implement IDisposable interface.A Dispose method should call the GC.SuppressFinalize method for the object it is disposing if the class has desturctor because it has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method. Reference: http://msdn2.microsoft.com/en-us/library/aa720161(VS.71).aspx

  3. Finalize

    A Finalize method acts as a safeguard to clean up resources in the event that your Dispose method is not called. You should only implement a Finalize method to clean up unmanaged resources. You should not implement a Finalize method for managed objects, because the garbage collector cleans up managed resources automatically. Finalize method is called by the GC implicitly therefore you can not call it from your code.

    Note: In C#, Finalize method can not be override, so you have to use destructor whose internal implementation will override the Finalize method in MSIL.But in the VB.NET, Finalize method can be override because it does support destructor method.

Actualización:Interesting semi-related thread here.

+0

'Solo debe implementar un método Finalize para limpiar los recursos no administrados': lo pone en Finalizar. Lo mismo con deshacerse? – hqt

+0

@hqt: Los casos en los que uno debería implementar 'Dispose' son mucho más numerosos que los que debería implementar un finalizador. Implemente 'Dispose' si es probable que una instancia de la clase o una clase derivada sea lo último que posea directamente un recurso no administrado, o que posea directamente lo último para poseer directamente un recurso no administrado, o que posea directamente lo último para poseerlo directamente, etc. Implemente 'Finalize' solo para la limpieza de recursos si la clase de uno directamente posee un recurso no administrado y casi nada más --un escenario mucho más estrecho. – supercat

+0

@hqt: si una clase posee directamente recursos no administrados y también contiene referencias a otros objetos, los recursos no administrados generalmente deberían dividirse en su propia clase finalizable (que idealmente no debería tener ninguna referencia fuerte a otra cosa), lo que significa que la clase que contiene referencias a otros objetos solo sería propietaria de "cosas que poseen directamente recursos no administrados", en lugar de poseer los recursos por sí mismos, y por lo tanto no necesitaría un finalizador. – supercat

50

Wikipedia tiene una buena discusión sobre la diferencia entre un finalizador y un destructor en el artículo finalizer.

C# realmente no tiene un destructor "verdadero". La sintaxis se asemeja a un destructor de C++, pero realmente es un finalizador. Usted ha escrito correctamente en la primera parte de su ejemplo:

~ClassName() { } 

Lo anterior es el azúcar sintáctica para una función Finalize. Garantiza la ejecución de los finalizadores en la base, pero por lo demás es idéntico a la anulación de la función Finalize. Esto significa que cuando escribe la sintaxis del destructor, realmente está escribiendo el finalizador.

According to Microsoft, el finalizador se refiere a la función que el recolector de basura llama cuando lo cobre (Finalize), mientras que el destructor es el trozo de código que se ejecuta como un resultado (el azúcar sintáctica que se convierte en Finalize). Están tan cerca de ser lo mismo que Microsoft nunca debería haber hecho la distinción.

El uso de Microsoft del término "destructor" de C++ es engañoso, porque en C++ se ejecuta en el mismo subproceso tan pronto como se elimina o se saca de la pila, mientras que en C# se ejecuta en un hilo separado en otro momento.

+0

Yo diría que tal distinción entre el destructor y el finalizador es importante. Sin embargo, solo aquellos que se preocupan por lo que sucede debajo del capó se preocupan por dicha distinción. –

+0

También tenga en cuenta que ECMA-334 ha desambiguado explícitamente "destructor" y "finalizador" formalmente, hace mucho tiempo. No sé por qué MS todavía insiste en el término engañoso en sus especificaciones. – FrankHB

+0

Al menos al trabajar con Mono, C# se modela realmente después de C++, y la mayoría de los objetos C# nativos son objetos C++. La forma en que el compilador que compiló Mono funciona dicta cómo se destruyen esos objetos C++, y del mismo modo, cómo la finalización del objeto C# se propaga a C++ y llama a esos destructores. La distinción tiene sentido bajo el capó, pero todavía no se aplica realmente a C#. – Kenzi

Cuestiones relacionadas