9
votes

Utiliser le destructeur / éliminer la classe de base?

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.

la question : 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 ()?

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.


10 commentaires

Veuillez ne faire que cela si vos "éléments privés" sont non gérés .


@HENK: Que les " privé é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 , 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 n'aurait besoin d'être à l'intérieur de la méthode wriditata , immédiatement après l'appel à senddatatowidget . 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.


4 Réponses :


16
votes

MSDN stipule que lestructeurs sont appelés automatiquement sur les classes de base. < / p>


1 commentaires

Merci nik! J'aurais dû lire plus loin que "les destructeurs ne peuvent être hérités ni surchargés".



6
votes

Vous devez suivre le modèle jetable ici. Il s'adresse également à l'héritage.

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.

Les enfants sont donc découplés des ressources non gérées de la classe de base. Ils peuvent remplacer disposer (bool) pour nettoyer leurs propres affaires.

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.

Dans une perspective de conception générale, une classe jetable serait mieux scellée.


1 commentaires

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É



0
votes

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)


0 commentaires

0
votes

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).

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).


0 commentaires