est-il légal de recréer une référence enracinée à 'this' dans un destructeur .net?
-
03-07-2019 - |
Question
Est-il légal d'écrire ce qui suit en .net?
public class A
{
public int i = 0;
~A()
{
Aref = this;
}
}
public static A Aref;
static void Main(string[] args)
{
Aref = new A();
int gen = GC.GetGeneration(Aref);
Aref = null;
GC.Collect(gen, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
Console.WriteLine(Aref.i);
Console.ReadLine();
}
Cela fonctionne et écrit «0» sur la console comme prévu, mais je me demande s’il est garanti que cela fonctionnera toujours.
Est-ce que quelqu'un sait ce qui se passe derrière la scène?
La solution
C'est ce qu'on appelle la résurrection, et c'est légal. Google pour ".net la résurrection d'objet" " (et des termes similaires) et vous trouverez des informations telles que:
Assurez-vous simplement que ces objets zombies ne reviennent pas et tentent de manger votre cerveau ou quelque chose du genre. Comme toute nécromancie, c'est dangereux. (Principalement parce que les finaliseurs plus haut dans la hiérarchie des classes peuvent avoir libéré des ressources essentielles. Notez également que le finaliseur ne sera pas exécuté une seconde fois si l'objet devient "non référencé", sauf si vous appelez GC.ReRegisterForFinalize
.)
Autres conseils
Cela fonctionne car la première collecte de place ne collecte pas l'instance. Il planifie simplement l'instance pour que son finaliseur soit exécuté. Le finaliseur crée ensuite une nouvelle racine pour l'instance. Ainsi, lors de la prochaine collecte, l'instance est réellement enracinée et ne peut donc pas être collectée.
Vous devriez être très prudent avec ce dur. Si le finaliseur est utilisé pour s'assurer qu'un objet est supprimé, cela enfreint le protocole car les modèles jetables indiquent qu'une instance supprimée doit émettre une exception ObjectDisposedException si elle est utilisée après avoir été supprimée.
Le ramasse-miettes divise les objets en trois groupes:
- Ceux qui sont toujours en vie, car il a été vérifié qu'une référence enracinée existait en dehors de la file d'attente de finalisation;
- doivent être supprimés, car aucune référence enracinée n'existe nulle part;
- Ceux qui doivent être finalisés, car une référence enracinée existe dans la file d'attente de finalisation, mais nulle part ailleurs.