en C # /. Net, y a-t-il un moyen d'obtenir une notification avant que l'objet pointé par une référence faible est détruit? Fondamentalement, je veux permettre à un objet de collecter, mais faire quelque chose juste avant que l'objet ne soit détruit, sans modifier le code pour ajouter des destructeurs (puisque je ne saurai exactement quels types d'objets seront poursuivis avec mon code). p>
merci, Robert p>
6 Réponses :
Non, il n'y a aucun moyen d'atteindre cette fonctionnalité. P>
Après un peu de spéculation, je ne crois pas qu'il soit possible de mettre en œuvre une fonctionnalité de la manière que vous décrivez. p>
Considérez qu'au point que l'objet détenu par une faiblesse est collecté, il n'y a plus de références (par conséquent, il est à collectionner). Pour qu'un événement soit utilisé pour vous, il aurait besoin de fournir à l'objet dans le cadre de l'événement. Cela signifie que la référence est passée de collectionner à la non-collective. Rien n'empêche le code de traitement de la rémission d'une référence sur cet objet. Par conséquent, l'objet ne peut plus être considéré comme à collectionner. Le CLR devra faire une deuxième passe sur l'objet de la ré-assuration qu'il a été collectable. p>
Vous pouvez voir comment la deuxième fois autour de l'événement ne pouvait être soulevée car elle conduirait à des objets non collectables. P>
Ce serait une mauvaise utilisation de la nommée de prétendre que cet événement a été soulevé juste avant qu'un objet ait été collecté. Tout simplement parce que tout gestionnaire pouvait empêcher cela d'être collecté en établissant une nouvelle référence à l'objet. Au lieu de cela, il devrait être "objetmaybeabouttobecollected". Cela ne vous donnera probablement pas le comportement que vous recherchez. p>
Cool, merci ... Pouvez-vous penser à toutes manières d'obtenir des fonctionnalités similaires autres que des faiblesses?
@ROBERT, autre que la forme de destructeurs / éliminer, je ne peux penser à rien au sommet de ma tête
Je suis absolument d'accord, de toute façon, les événements faibles pourraient faire le tour! Une petite capture, ils n'existent pas dans C # pour que vous puissiez la mettre en œuvre (c'est un peu délicat mais essentiellement possible).
Votre question n'a pas de sens pour moi. Où est le code qui va être appelé censé résider? Étant donné que les faibles références seront annulées avant que l'objet référencé ne soit détruit, il n'a pas de sens que cela pourra faire partie de la classe qui a référencé l'objet détruit à peu près à être détruit. Et il y a déjà un code dans l'objet référencé qui s'appelle avant que l'objet ne soit détruit - c'est le destructeur. P>
Quel est le problème de conception réel que vous souhaitez résoudre? Il peut y avoir une meilleure façon. P>
Je souhaite créer un système dans lequel les objets sont enregistrés pour être sérialisé au serveur de temps en temps. Les données sérialisées seront appuyées sur le serveur toutes les quelques minutes (hors de mon contrôle), de sorte que les données sérialisées de tous les objets enregistrés sont alors calculées. Toutefois, si un objet enregistré est désttruction, je souhaite calculer le droit de données avant de décéder (et que les données seront envoyées avec le lot suivant sur le serveur).
Cela semble toujours un peu funky. Si vous souhaitez envoyer des données sérialisées à un serveur périodiquement, pourquoi pas seulement avoir l'objet qui est responsable de la série de sérialisation maintenue une référence (non autofe) aux objets enregistrés et les libérons une fois qu'ils ont été téléchargés? Compte tenu de l'imprévisibilité du chronométrage destruction, vous ne voudrez pas en dépendre de l'intégrité des données, de toute façon.
Ils doivent rester sérialisés de temps en temps aussi souvent qu'ils sont vivants / changeants. C'est des préférences d'interface utilisateur Silverlight (c'est-à-dire des largeurs de colonne, etc.), de sorte que les éléments de l'interface utilisateur sont toujours autour, leur état doit être enregistré sur le serveur.
Vous ne pouvez pas faire ça. Cependant, ce que vous pouvez faire est de surveiller quand un GC s'approche (il existe de nouvelles aptituées GC dans CLR V3.5SP1 qui vous permet de le faire, des gcnotitions) p>
Je suppose que c'est aussi naturel un lieu pour mettre à jour les données sérialisées. Merci pour l'info!
Pour ce que vous décrivez, les finaliseurs seraient une méthode de meilleure qualité. P>
Il serait possible d'avoir une sémantique similaire à ce que vous décrivez si une référence faible avec un notifiant a été considérée de la même manière à un objet avec un finisseur, qui consiste à dire que lorsque l'objet a été considéré comme étant considéré comme intéressant à personne , il serait mis en file d'attente pour la finalisation et la notification; L'entrée de la file d'attente serait considérée comme une référence en direct, de sorte que l'objet ne serait pas réellement collecté avant d'être agi. P>
Étant donné que ce n'est pas possible, la meilleure approche réalisable pourrait probablement être tout "je suis intéressé par cet objet" Les références indiquent à un objet wrapper léger qui ferait à son tour sur l'objet réel et avoir le " Des références faibles "pointent sur une autre emballeuse qui dirigerait également l'objet réel. Le premier wrapper doit contenir une référence à la seconde, mais pas vice versa. Le premier wrapper doit avoir un finaliseur qui déclenchera le code approprié lorsqu'il sort hors de portée. P>
Malheureusement, je n'ai pas vu de mise en œuvre complète d'une telle stratégie. Il y a quelques mises en garde importantes à considérer. Parmi eux: (1) Les finaliseurs ne devraient jamais attendre des serrures, ni quoi que ce soit qui puisse jeter une exception; (2) le code qui accède à d'autres objets qui aurait pu être hors de portée doit être préparé pour la possibilité que d'avoir déjà été finalisés, être en cours de finalisation, en attente de finalisation, sinon avoir des références en direct ailleurs; (3) Si un finaliseur stocke une référence enracinée à un objet finalisable qui a été trouvé éligible pour la collecte des ordures, un tel objet peut être finalisé même si la référence en direct existe. P>
.NET 4.0 a la solution dont vous avez besoin: conditionné . Voici un court programme qui démontre l'idée. (discuté ici aussi)
using System; using System.Runtime.CompilerServices; namespace GCCollectNotification { class ObjectToWatch { } class Notifier { public object ObjectToWatch { get; set; } ~Notifier() { Console.WriteLine("object is collected"); } } class Program { private ConditionalWeakTable<object, Notifier> map = new ConditionalWeakTable<object, Notifier>(); public void Test() { var obj = new ObjectToWatch(); var notifier = map.GetOrCreateValue(obj); notifier.ObjectToWatch = obj; } static void Main(string[] args) { new Program().Test(); GC.Collect(); GC.WaitForPendingFinalizers(); // "object is collected" should have been printed by now Console.WriteLine("end of program"); } } }