en C #, comme mentionné dans le Documentation , et Cette belle post a accepté la réponse, il est déclaré que les classes Don 't hériter le destructeur de leur classe mère. p>
la question forte>:
Si je veux m'assurer de disposer de disposer des éléments privés de la classe de base, est le moyen approprié de mettre en œuvre Idisposable dans toute la classe enfant et dans la méthode d'expiration, appelez la base.Dispose ()? P>
On dirait bien de le faire, mais j'aurais préféré un moyen qui ne nécessiterait pas la mise en œuvre dans toutes les classes d'enfants. P>
4 Réponses :
MSDN stipule que lestructeurs sont appelés automatiquement sur les classes de base. < / p>
Merci nik! J'aurais dû lire plus loin que "les destructeurs ne peuvent être hérités ni surchargés".
Vous devez suivre le modèle jetable ici. Il s'adresse également à l'héritage. p>
La partie intéressante ici est "destructeurs n'hérité pas", je ne suis pas sûr de quoi faire cela. J'ai écrit un petit test mais à mon soulagement, il suffit d'écrire un destructeur dans la classe de base. p>
Les enfants sont donc découplés des ressources non gérées de la classe de base. Ils peuvent remplacer Mais j'ai fait un commentaire parce que je vois trop de programmeurs à mettre en œuvre le modèle complet pour gérer les ressources gérées. p>
Dans une perspective de conception générale, une classe jetable serait mieux scellée. p> disposer (bool) code> pour nettoyer leurs propres affaires. p>
Merci henk. Je vais comparer le modèle que vous avez lié à ce que j'ai fait et faire l'ajustement nécessaire, juste pour le souci d'exactitude! :-RÉ
La classe de base doit utiliser le motif standard Idisposable pour les classes de base - de cette façon, seule la classe de base a besoin d'un finaliseur et des cours dérivés simplifient simplement la méthode virtuelle
protected void Dispose(bool disposing)
Si la classe mère utilise le motif iDisposable de Microsoft, la classe enfant ne doit pas remplacer le dispositif d'éliminer (void), mais à la place, le disposer de l'élimination (élimination booléenne). Si appelé avec l'élimination de vrai, il devrait disposer de la classe enfant et appelle la base.Dispose (vrai). Si appelé avec l'élimination de faux, il ne devrait dans la plupart des cas rien sauf Call Base.Dispose (faux). P>
Notez que dans la plupart des cas, l'appel à la base.Dispose (faux) ne fera rien, mais cela devrait être fait de toute façon. Si la classe enfant devra ajouter des "ressources non gérées" supplémentaires (c'est-à-dire s'il a des responsabilités supplémentaires à effectuer dans un finaliseur), elle devrait généralement encapsuler ces responsabilités dans un autre objet. Notez que la question de savoir si une classe a un finaliseur n'est pas simplement un "détail de mise en œuvre"; L'ajout d'un finaliseur à une classe de base peut être un changement de rupture, provoquant un programme qui aurait des ressources divulguées (mauvais, mais peut-être survivable si le programme ne fonctionne pas trop longtemps à la fois) dans une fois, sur des occasions aléatoires , tenter de nettoyer les ressources qui sont toujours utilisées (ne causent souvent pas de problèmes, mais peuvent causer des défaillances rares mais immédiates). P>
Veuillez ne faire que cela si vos "éléments privés" sont non gérés b>.
@HENK: Que les " privé i> éléments" de la classe de base ne soient pas gérées sont un détail de mise en œuvre que les classes d'enfants ne devraient pas vraiment se soucier de. Si votre classe de base implémente
Idisposable code>, il doit être éliminé.
Dans ce cas, les éléments privés de la classe de base sont en effet des ressources non gérées, mais comme Lukeh a dit, les classes d'enfants ne sont pas «au courant».
@Lukeh: La mise en œuvre isisposable et devoir être disposée sont distinctes d'avoir (besoin) d'un destructeur.
@LUKEH: Si une classe ou sa classe mère implémente un finisseur, elle et toutes les classes dérivées devront probablement utiliser GC.Sekeekalive dans de nombreux cas, ce qui n'était pas nécessaire autrement nécessaire (sinon risquer des défaillances aléatoires). Ce n'est pas un "détail de mise en œuvre" privé. Si .NET a fourni un moyen de marquer une classe de manière à obliger la gigue à toujours se considérer comme en direct, la question de la finalisation pourrait être abstraite, mais je ne suis pas au courant de ces moyens.
@supercat: Je ne suis pas vraiment sûr de ce que vous voulez dire. Avez-vous un exemple et / ou plus de détails sur la manière dont l'une de ces "défaillances aléatoires" pourrait se produire?
@Lukeh: Supposons qu'une classe détient une poignée non gérée dans un widget (un périphérique plug-in) et une méthode Writeata, comme sa toute dernière action, appelle senddaThatowidget (widgethadle, datatosend). Si la classe n'a pas de finaliseur et qu'elle est abandonnée, le widget peut être laissé dans un état inutilisable (sauf si ou jusqu'à ce que cela puisse sortir ou quelque chose), mais le comportement sera déterministe. Si un objet (E.G. Fred) a un finisseur, cependant, un problème peut se produire si le code qui détient la dernière référence aux appels Fred Fred.writedata avant de l'abandonner. Fred deviendrait admissible à la collection de la poubelle ...
@Lukeh: ... dès qu'il appelle SendDatatowididget () - Avant que cet appel ne revienne. Par conséquent, le collecteur des ordures pouvait finir par exécuter le finaliseur pour Fred, tuant le widget spécifié par WidGetHandle, tandis que l'opération SendDatatowidge était toujours en cours.
@supercat: Sûrement de l'appel à
Keepalive code> n'aurait besoin d'être à l'intérieur de la méthode code> wriditata code>, immédiatement après l'appel à
senddatatowidget code>. Toute sous-classes ou sites d'appels n'aurait pas besoin d'être conscient de cela, ou serait-ce?
@Lukeh: tout ce qui utilise une partie de l'objet qui sera invalidé par le finaliseur, mais ne tient pas une référence à l'objet dans son ensemble aura besoin d'une maintenance. Dans certains cas, il est possible que toutes les trucs de conserve soient dans la classe des parents, mais dans certains cas, la classe enfant peut en avoir besoin.