2009-06-29 4 views
1

Dans C#, je désérialise un objet d'un type qui implémente IDisposable avec l'instruction suivante (à titre d'illustration uniquement). Afaik, le sérialiseur tente de construire l'objet en utilisant le ctor par défaut et en affectant par la suite toutes les propriétés publiques et tous les champs. Au cas où il y aurait une exception, je ne mettrai pas la main sur l'objet construit. Donc, ma question est de savoir s'il y a moyen de s'assurer que les ressources allouées sont libérées automatiquement. Je suis conscient du Dispose (bool disposing) - 'pattern' implémentant un finaliseur explicite, mais je me sentirais plus à l'aise avec la libération explicite de toutes les ressources (c'est-à-dire de façon déterministe).Existe-t-il un moyen de s'assurer que Dispose() est appelé en exception lors de la désérialisation d'une classe IDisposable?

+0

Je pense que si vous utilisez ce type de fonctionnalité, observez un cadre de persistance différent, ouvert et adaptez-le. En pratique, je n'ai pas touché ce cas limite. –

+0

Suite à la réponse de Sam - hey j'en ai un qui pourrait fonctionner ;-p (mais ce n'est pas xml). Il ne serait pas * difficile * de suivre tous les objets pour 'IDisposable'. Je ne serais pas pressé d'ajouter cela, mais ça pourrait marcher. –

Répondre

3

Il semble que le cas inhabituel pour un DTO à fait ont ressources à DEALLOCATE, donc je peux comprendre si elle ne fournit pas IDisposable soutien en cas d'échec (mon sérialiseur ne fonctionne pas, que ce soit - donc je peux certainement » t critiquer). Peut-être changer votre classe de sorte que si a a des ressources à disposer, il prend ces ressources paresseusement (c'est-à-dire pas seulement quand le type est désérialisé).

XmlSerializer ne prend pas en charge les rappels, sinon le rappel final serait une option possible pour charger avec impatience les ressources (un peu hacky, cependant).

+1

L'approche paresseuse ressemble à la solution la plus sensée – RichardOD

+0

Vous avez raison à propos du point DTO-should-not-own-resources. J'essayais de contourner l'approche explicite de DTO et d'utiliser le dotnet xmlserializer hors de la boîte. cependant, il semble que ce soit plutôt problématique dans mon cas (comme toujours, en essayant de sérialiser xml en classes non triviales) ---. –

0

Votre constructeur par défaut fait-il quelque chose qui nécessiterait une disposition? Si oui, est-ce une bonne idée (en particulier pour un objet destiné à être sérialisé en XML)? Si non, pourquoi vous en inquiétez-vous? Laissez le garbage collector ...

[Edit: le point sur les champs Removed publics, depuis sa incorrecte]
Je laisse également cette réponse disponible pour toute valeur éducative, il peut avoir -> lire de Marc commentaire

+0

Les champs publics sont assignés (bien que vous ne devriez pas avoir des champs publics en premier lieu, bien sûr); ce sont les membres privés qui ne le sont pas. Et ce n'est pas seulement le constructeur que vous devez prendre en compte - il pourrait échouer à tout moment, et il pourrait ne pas être lié à cette classe/instance. –

+0

Silly moi ... je suis tellement habitué à avoir que des champs privés, j'ai oublié la différence ... Et bon point sur d'autres échecs possibles ... –

0

Si une exception est générée à l'intérieur de la méthode XmlSerializer.Deserialize, elle sera propagée à la méthode catch suivante et votre objet (o) ne sera pas affecté. Donc, à moins que vous n'utilisiez les setters de propriétés pour allouer des ressources non managées pendant la désérialisation, je ne vois pas pourquoi vous devriez vous préoccuper de l'élimination manuelle de l'objet.

Mais si votre classe alloue des ressources non managées, implémenter correctement IDisposable signifiera que vous allez également libérer des ressources non managées du finaliseur de votre objet, ce qui devrait suffire. Il n'y a pas d'autre moyen d'appeler Dispose() sur un objet qui n'a pas été affecté en premier lieu. Cela dit, je dois dire à admin que j'ai eu plusieurs occasions où XmlSerializer se bloquerait si le fichier xml n'était pas complètement valide pendant la désérialisation - donc j'ai fini par faire la validation du schéma avant la désérialisation, juste pour être sûr que tout se passe bien .

0

Comment appeler GC.Collect (0, GCCollectionMode.Forced) après avoir obtenu l'exception?

+0

je n'oserais pas ... façon de laid –

+0

mais cela fonctionne :-P LOL – anonymous

+0

vous ne devriez jamais forcer le GC explicitement. –

1

Une clause using est ce que vous utilisez pour libérer des ressources: déterministe

using (MyDisposible o = (MyDisposible)s.Deserialize (filepath)) 
{ 
// Do stuff with 0 
} 

Je me demande pourquoi vous voulez le faire bien. En C#, vous ne voulez que libérer des choses déterministes si elles sont liées à une ressource physique externe comme une connexion SQL ou un fichier.

Un garbage collector est asymptotiquement plus efficace que la gestion manuelle de la mémoire et c'est une bonne pratique de permettre aux références de la mémoire d'être simplement hors de portée pour être libérées.

+0

"Un garbage collector est asymptotiquement plus efficace que la gestion manuelle de la mémoire et c'est une bonne pratique de permettre aux références de la mémoire d'être simplement hors de portée pour être libérées." Attendez, donc vous prétendez que C++ ou C serait plus rapide \ plus efficace avec le garbage collection? Ce n'est pas correct. La gestion manuelle de memeory est toujours plus efficace que la collecte automatique des ordures, même si elle est bonne. –

+0

Inaccurate. Comme pour la plupart des choses, la réponse est "dépend de la façon dont vous l'utilisez". http://www.hpl.hp.com/personal/Hans_Boehm/gc/04tutorial.pdf – clemahieu

+0

@the_drow: Le GC offre un avantage au-delà de l'efficacité de l'exécution: il est très difficile de rendre un système non GC robuste contre les références à la destruction objets.Même si l'on utilise principalement la gestion manuelle des ressources, un système GC peut assurer que tant qu'une référence existe, sa cible restera au moins assez bien pour être reconnue comme un objet disposé. Sinon, si l'espace était réutilisé, ce qui était une référence à un objet mort pourrait devenir une référence à un objet vivant - mais totalement indépendant. – supercat

0

Le broyeur et le finaliseur ne sont PAS la même chose en C#.

Un éliminateur implémente un appel pour disposer explicitement des ressources utilisées, mais pas de la mémoire qu'elles contiennent. L'utilisateur de votre objet est requis de l'appeler.

Vous pouvez utiliser un finaliseur en C# pour garantir que même si votre broyeur n'est pas appelé, vous ne perdez pas de ressources. i.e .Net garantit qu'il va essayer pour exécuter votre broyeur avant qu'il ne soit réellement collecté.

XmlSerializer est responsable dans son appel de ne pas fuir la mémoire s'il y a une exception dans l'appel. Si cela arrive, vous aurez trouvé un bug dans .Net et n'hésitez pas à le signaler. Si vous appelez deserialize et qu'il déclenche une exception, vous ne récupérez pas l'objet, il est parti ...

Le collecteur d'ordures de .Net fonctionne d'ailleurs, c'est l'un des avantages que vous obtenez avec un langage géré, en que vous n'avez pas à vous soucier de nettoyer votre mémoire (dans la plupart des cas) pour que vous puissiez vous concentrer davantage sur ce que fait votre code et bien le faire.

+0

@Spence: À quoi répond cette réponse? Je n'ai vu aucune raison de croire que le PO pense que les deux sont les mêmes. OBTW, jamais entendu le terme "Disposer" avant. –

+0

Clarification aux paragraphes 1, 2, 3. répondre en 4/5. Je crois que j'ai affaire à un codeur en C++ donc je voulais clarifier la différence entre un broyeur et un finaliseur qui est une erreur commune faite par ceux qui traversent le gouffre. – Spence

Questions connexes