2016-06-28 2 views
0

Contexte:Faire un objet géré vraiment supprimables

J'ai essayé de poser this question yesturday mais sans véritable conclusion, donc je pensais que je voudrais essayer de demander d'une manière différente que ce problème me cause un grand mal de tête .

Mon application est un outil de conception IHM intégré. Cela permet à l'utilisateur (qui est un développeur interne) de concevoir visuellement l'apparence de l'IHM intégrée et, ensuite, en cliquant sur un bouton, de générer le code C. La plupart de cela fonctionne maintenant.

L'un des principaux avantages de l'outil est qu'il permet à l'utilisateur de créer de nouveaux écrans (qui peuvent alors contenir des contrôles). Dans mon application, un «écran» est un objet. Quand un nouvel écran est ajouté, il est placé dans un List<Screen> qui est ensuite utilisé pour générer le code C.

L'une des propriétés de cet écran est le private Screen nextScreen qui est une référence à un autre objet d'écran qui indique quel écran afficher ensuite lorsque le bouton de navigation est enfoncé. Encore une fois tout cela fonctionne très bien.

Problème:

Cependant, lors de la lecture avec l'outil pour générer du code nous avons trouvé un problème. 2 écrans ont été créés, le premier écran ayant sa propriété nextScreen définie sur le 2ème. Un peu plus tard, il a été décidé que le deuxième écran était erroné, donc il a été supprimé et un nouvel écran a été créé. Cependant, ils ont oublié de définir la propriété nextScreen du premier écran sur ce nouvel écran, donc il faisait toujours référence à l'écran d'origine qui, visuellement, avait été supprimé.

Lorsque le code a été généré, le code C résultant n'a pas pu être compilé car le premier écran faisait référence à un écran qui, dans l'environnement C généré, n'existait pas.

Question:

Alors ma question est de savoir comment puis-je mettre en œuvre une meilleure façon de supprimer ce qui garantit que tout ce qui fait référence à un objet « supprimé » le sait et définit cette propriété sur null?

Pensées à ce jour:

1) J'ai essayé de créer la propriété « nextScreen » comme WeakReference qui fonctionne, mais cela signifie que je dois appeler manuellement le GC.Collect() chaque fois qu'un effacement est fait ... pas idéal de ma compréhension! (Mon exemple d'essayer ceci peut être trouvé dans le lien en haut de ce billet)

2) Je pourrais, après suppression, vérifier tous les objets pour une référence à celui qui est supprimé et le mettre à null. Cependant, ce que j'ai décrit ci-dessus n'est que l'un des nombreux objets composant l'IHM, dont la plupart ont une ou plusieurs références à d'autres objets. Donc, cela pourrait être lent et dans mon esprit ne semble pas juste.

3) Peut-être utiliser IDisposable ??? mais à ma connaissance, c'est pour le code non géré!

Toutes les idées ou les domaines pour que je puisse lire sur ce serait génial car je suis en train de me tirer les cheveux sur ce ... pas que j'ai beaucoup !!!

Répondre

0

Je pense que vous pouvez utiliser modèle ObjectPool pour créer et supprimer des objets et certains Wrapper là-dessus est des objets, de contrôler leur livetime

+0

Merci pour la suggestion que j'ai examinée, mais cela ne fournit pas vraiment la fonctionnalité dont j'ai besoin comme décrit ci-dessus. J'ai continué à enquêter et suis arrivé à la conclusion qu'il n'y a vraiment rien pour mon but, qui me supprime vraiment. Je suis donc en train de mettre en place ma propre classe de gestionnaire et une interface de support que je publierai une fois terminée. – TheGrovesy

0

L'un des impératifs de conception fondamentaux du GC est s'il y a un moyen par lequel code peut rencontrer une référence à un objet, l'objet continuera à exister. Il n'y a aucun moyen de "supprimer" un objet de sorte que les références à celui-ci deviendront invalides. Il y a, cependant, deux choses que vous pouvez faire:

  1. Demandez à votre classe inclure un champ qui indique si elle a été invalidée et que le code qui reçoit ou suit une référence à une instance de classe, vérifiez que champ Assurez-vous que l'instance est toujours valide. Si le code définit ce champ dans une instance, toutes les références ne seront plus des références à une instance valide, mais deviendront (par définition) des références à une instance invalide.

  2. Si vous créez un WeakReference à un objet, la propriété Target de cette WeakReference deviendra null lorsque le GC détecte aucune référence non faible à la cible existe (si une référence à une cible non nul est copié une autre variable, cette variable gardera la cible en vie même si la référence faible était la seule chose dans l'univers avec une référence à la cible). Le fait de forcer un cycle complet de collecte des ordures annulera généralement immédiatement toute référence faible à des objets qui ne sont référencés nulle part, mais représenterait un abus du système GC. Mettre en œuvre une routine "trouver tous les objets utilisés" qui compte combien de fois il a été exécuté, et avoir un champ dans chaque instance de classe dans laquelle cette routine va stocker son compteur. Tout objet qui devrait être considéré comme "utilisé" contiendra la valeur du compteur de routine "trouver tous les objets utilisés" qui a été tenu la dernière fois qu'il a été exécuté. C'est un peu comme ce que le GC fait avec les objets qu'il connaît, mais si vous le faites vous-même, vous pouvez décider quelles formes de référence devraient justifier qu'un objet soit "utilisé".

+0

pouvez-vous développer votre troisième point un peu plus. Cela semble intéressant mais je ne suis pas complètement comment cela fonctionnerait. Merci. – TheGrovesy

+0

Conceptuellement, pensez à chaque objet comme ayant un champ "dernier accès", et ayant un processus qui "accède" à tout ce qu'il peut trouver d'une manière ou d'une autre, mettant à jour le champ de manière appropriée dans chaque objet rencontré. Si un objet n'a pas été accédé depuis la dernière fois qu'une analyse a été effectuée depuis, cela signifie qu'il n'est pas possible qu'un balayage effectué de cette manière trouve l'objet. L'utilisation du temps réel «horloge-mur» pour le dernier accès nécessiterait toutefois de stocker suffisamment de précision, presque inutile, pour distinguer les objets dont le dernier accès ... – supercat

+0

... a précédé le début de l'analyse par rapport à ceux dont le dernier accès a eu lieu pendant l'analyse. Le remplacement de l'horloge par un compteur incrémenté au début de chaque analyse permet d'éviter ce problème. – supercat

0

Vous pouvez créer une nouvelle classe générique appelée Deletable<T> pour envelopper vos objets. Il fonctionnerait comme Nullable<T> en ce qu'il contient une propriété de type T qui contient la valeur d'origine. Il aurait besoin d'une propriété en lecture seule boolIsDeleted qui indique si la valeur encapsulée a été supprimée et une méthode Delete qui annule la valeur encapsulée et définit l'indicateur IsDeleted.

Tout ce qui utilise les objets Screen passerait à Deletable<Screen>. Lorsqu'un écran est supprimé, appelez Delete sur le wrapper. Tout code qui se soucie si un écran est supprimé peut simplement vérifier scr.IsDeleted avant d'utiliser scr.Value.

Cela permettra à la récupération de place pour nettoyer tous les objets volumineux, tout en laissant une petite valeur "flag" à sa place que vous pouvez utiliser pour vérifier si l'objet réel a été supprimé.

+0

merci pour l'entrée. idée intéressante ... je ne savais pas non plus sur Nullable . En utilisant la suggestion d'utilisation cependant, vous dites que cela permettrait au garbage collector de nettoyer, mais est-ce vrai? Comme je suppose que l'objet Deletable tiendra toujours une référence à l'objetc réel ne serait pas recueilli ?? – TheGrovesy

+0

D'autres objets contiennent uniquement une référence à l'encapsuleur. La seule référence à l'objet réel est dans l'encapsuleur. Lorsque vous appelez Delete sur le wrapper, il annule la seule référence, la rendant disponible pour la récupération de place. –