2009-06-29 4 views
1

In C# deserialisiere ich ein Objekt eines Typs, der IDisposable mit der folgenden Anweisung implementiert (nur zur Veranschaulichung).Gibt es eine Möglichkeit, sicherzustellen, dass Dispose() bei der Deserialisierung einer IDisposable-Klasse für eine Ausnahme aufgerufen wird?

afaik, der Serializer versucht, das Objekt mit dem Standard-Ctor zu konstruieren und anschließend alle öffentlichen Eigenschaften und Felder zuzuordnen. Falls eine Ausnahme ausgelöst wird, erhalte ich das konstruierte Objekt nicht.

Also, meine Frage ist, ob es einen Weg gibt, um sicherzustellen, dass noch zugewiesene Ressourcen automatisch freigegeben werden. Ich bin mir des Dispose (bool disposing) - "Musters" bewusst, das einen expliziten Finalizer implementiert, aber ich würde mich wohler damit fühlen, alle Ressourcen explizit (d. h. deterministisch) zu befreien.

+0

Ich denke, dass, wenn Sie diesen Rand Fall schlagen und einen absoluten Bedarf für diese Art von Feature haben, betrachten Sie ein anderes, offenes, Persistenz-Framework und passen Sie es an. In der Praxis habe ich diesen Randfall nicht getroffen. –

+0

Im Anschluss an Sams Antwort - hey, ich habe einen, der vielleicht funktioniert ;-p (aber es ist kein xml). Es wäre nicht so schwer, alle Objekte für IDisposable zu verfolgen. Ich würde es nicht eilig haben, das hinzuzufügen, aber es könnte funktionieren. –

Antwort

3

Es scheint, den ungewöhnlichen Fall für ein DTO tatsächlich haben Ressourcen freizugeben, kann ich so verstehen, wenn es nicht IDisposable Support bietet bei Ausfall (meine eigenen Serializer nicht, entweder - so sicher, ich kann‘ t kritisieren).

Vielleicht ändern Sie Ihre Klasse, so dass, wenn es hat Ressourcen zu entsorgen, dauert es diese Ressourcen träge (d. H. Nicht nur, wenn der Typ deserialisiert).

XmlSerializer unterstützt keine Callbacks, sonst wäre der letzte Callback eine mögliche Option, Ressourcen schnell zu laden (ein bisschen hacky, obwohl).

+1

Der faule Ansatz klingt wie die vernünftigste Lösung – RichardOD

+0

Vermutung, dass Sie mit dem Punkt DTO-sollte-nicht-eigene-Ressourcen recht haben. Ich habe versucht, den expliziten DTO Ansatz zu umgehen und benutze den dotnet xmlserializer aus der Box. scheint jedoch in meinem Fall eher problematisch zu sein (wie immer, wenn ich versuche, nichttriviale Klassen zu xml-serialisieren). –

0

Macht Ihr Standardkonstruktor etwas, das eine Entsorgung erfordern würde? Wenn ja, ist das eine gute Idee (besonders für ein Objekt, das in xml serialisiert werden soll)? Wenn nein, warum machst du dir dann Sorgen? Lassen Sie es für den Garbage Collector ...

[Edit: Entfernte Punkt über den öffentlichen Bereichen, da seine falsche]
Ich verlasse auch diese Antwort für jeden erzieherischen Wert es haben kann -> lesen Marcs

+0

Öffentliche Felder werden zugewiesen (obwohl Sie an erster Stelle natürlich keine öffentlichen Felder haben sollten); Es sind private Mitglieder, die es nicht sind. Und es ist nicht nur der Konstruktor, den Sie berücksichtigen müssen - er könnte zu irgendeinem Zeitpunkt fehlschlagen und er könnte nicht mit dieser Klasse/Instanz in Verbindung stehen. –

+0

Silly me ... Ich bin so daran gewöhnt, nur private Felder zu haben, habe ich über den Unterschied vergessen ... Und guter Punkt über andere mögliche Fehler ... –

0

Wenn innerhalb der XmlSerializer.Deserialize Methode eine Ausnahme ausgelöst wird, wird sie an die nächste Fangmethode weitergegeben, und Ihr Objekt (o) wird nicht zugewiesen. Wenn Sie also die Eigenschaften-Setter nicht dazu verwenden, einige nicht verwaltete Ressourcen während der Deserialisierung zuzuweisen, sehe ich nicht, warum Sie sich darum kümmern sollten, das Objekt manuell zu entfernen.

Wenn Ihre Klasse jedoch nicht verwaltete Ressourcen zuweist, bedeutet die ordnungsgemäße Implementierung von IDisposable, dass Sie auch nicht verwaltete Ressourcen vom Finalizer Ihres Objekts freigeben, sodass dies ausreichen sollte. Es gibt keine andere Möglichkeit, Dispose() für ein Objekt aufzurufen, das nicht an erster Stelle zugewiesen wurde.

Nachdem ich das gesagt habe, musste ich mehrere Male XmlSerializer hängen, wenn die XML-Datei während der Deserialisierung nicht vollständig gültig war - also habe ich vor der Deserialisierung eine Schema-Validierung durchgeführt, um sicherzugehen, dass alles gut geht .

0

Wie wäre es mit GC.Collect (0, GCCollectionMode.Forced) nach Erhalt der Ausnahme?

+0

Ich würde es nicht wagen ... Weg zu hässlichen –

+0

aber es funktioniert: -P LOL – anonymous

+0

Sie sollten GC nie explizit erzwingen. –

1

A using Klausel ist, was Sie determinis freie Ressourcen nutzen:

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

Ich würde fragen, warum Sie dies allerdings tun wollen. In C# wollen Sie nur Dinge deterministisch freigeben, wenn sie an eine externe physische Ressource wie eine SQL-Verbindung oder eine Datei gebunden sind.

Ein Garbage Collector ist asymptotisch effizienter als die manuelle Speicherverwaltung, und es empfiehlt sich, Speicherreferenzen einfach aus dem Bereich zu entfernen, um freigegeben zu werden.

+0

"Ein Garbage Collector ist asymptotisch effizienter als die manuelle Speicherverwaltung, und es ist eine gute Vorgehensweise, Speicherreferenzen einfach zu erlauben, den Bereich zu verlassen, um freigegeben zu werden." Warten Sie, also behaupten Sie, dass C++ oder C schneller mit der Garbage Collection effizienter wäre? Das ist nicht korrekt. Manuelle Speicherverwaltung ist immer effizienter als automatische Speicherbereinigung, egal wie gut sie ist. –

+0

Ungenau. Wie bei den meisten Dingen ist die Antwort "hängt davon ab, wie Sie es verwenden". http://www.hpl.hp.com/personal/Hans_Boehm/gc/04tutorial.pdf – clemahieu

+0

@the_drow: GC bietet einen Vorteil, der über die Effizienz der Ausführungszeit hinausgeht: Es ist sehr schwierig, ein Nicht-GC-System robust gegen Verweise auf Zerstörte zu machen Objekte.Selbst wenn man hauptsächlich manuelle Ressourcenhandhabung verwendet, kann ein GC-System sicherstellen, dass, solange eine Referenz existiert, das Ziel mindestens so gut bleibt, dass es als ein entsorgtes Objekt erkennbar ist. Andernfalls, wenn der Raum wiederverwendet wurde, könnte eine Referenz auf ein totes Objekt eine Referenz zu einem lebenden - aber völlig unabhängigen - Objekt werden. – supercat

0

Disposser und Finalizer sind NICHT das gleiche in C#.

Ein Disponent implementiert einen Aufruf, um die verwendeten Ressourcen explizit anzugeben, jedoch nicht den darin enthaltenen Speicher. Der Benutzer Ihres Objekts muss dies aufrufen.

Sie können einen Finalizer in C# verwenden, um sicherzustellen, dass selbst wenn Ihr Entsorger nicht aufgerufen wird, keine Ressourcen verloren gehen. d. Net garantiert, dass es versuchen wird, Ihren Entsorger laufen, bevor es tatsächlich Müll gesammelt.

XmlSerializer ist in seinem Aufruf verantwortlich, Speicher nicht zu verlieren, wenn eine Ausnahme in dem Aufruf ist. Wenn dies der Fall ist, haben Sie einen Fehler in .Net gefunden und können es melden. Wenn Sie deserialize aufrufen und es eine Ausnahme auslöst, erhalten Sie das Objekt nicht zurück, es ist weg ...

. Net Müllsammler funktioniert übrigens, es ist eine der Werbegeschenke, die Sie mit einer verwalteten Sprache erhalten, in dass Sie sich in den meisten Fällen keine Gedanken über die Bereinigung Ihres Speichers machen müssen, damit Sie sich mehr auf das konzentrieren können, was Ihr Code tut, und das richtig machen.

+0

@Spence: Was ist das eine Antwort auf? Ich sah keinen Grund zu glauben, dass das OP denkt, dass die beiden gleich sind. OBTW, habe noch nie den Begriff "Disponent" gehört. –

+0

Klarstellung in den Absätzen 1, 2, 3. Antwort in 4/5. Ich glaube, ich habe es mit einem C++ - Coder zu tun, also wollte ich den Unterschied zwischen einem Entsorger und einem Finalisierer klären, was ein häufiger Fehler ist, der von denjenigen gemacht wird, die die Kluft überschreiten. – Spence

Verwandte Themen