Benutzer mit den meisten Antworten
XmlSerializer: Ausnahme für einzelne Objekte einer Liste

Frage
-
Hi,
Ich serialisiere in einer Anwendung ein Objekt, welches eine ObservableCollection von Objekten enthält.
Jetzt möchte ich zur Laufzeit einzelne Objekte dieser Liste von der Serialisierung ausnehmen, so dass z.B. nur Objekte mit der Property IsSaveable == true ins XML gespeichert werden.
Jemand eine Idee wie man das elegant machen kann?
Konnte trotz vielem Lesen und googlen nichts hilfreiches finden.
Antworten
-
Hi,
ich persönlich würde, wenn mir das so sehr am Herzen liegt, alle Klassen von einer Schnittstelle ableiten oder eben eine Basisklasse mit dieser Eigenschaft erstellen und alle relevanten Klassen dann von dieser Klasse erben lassen. Mit einem Attribut könnte man dann auch gleich angeben, welche Eigenschaft(en) für die Steuerung der Serialisierung zuständig ist.
Es gibt verschiedene Mechanismen, mit denen man die (XML) Serialisierung steuern kann, bspw.:
Private _Age As Int64 <System.Xml.Serialization.XmlIgnoreAttribute> _ Public AgeSpecified As Boolean = False <XmlAttribute()> _ Public Property Age() As Int64 Get Return _Age End Get Set _Age = Value If Value > 0 Then AgeSpecified = True End If End Set End Property
Letztendlich kann man sich also auch selbst etwas ähnliches bauen, dass das für Objekte in einer Liste macht. Allerdings wird man sich dafür dann wohl auch einen eigenen Serialisierer erstellen müssen, da die Standardklassen das nicht kennen.
Wie gesagt, ich sehe deine Anforderung als zu speziell bzw. zu weit gefasst (wenn man die ggfs. in Frage kommenden anderen Anforderungen anderer User berücksichtigt) als dass Microsoft das von Haus aus ins .NET Framework einbauen müsste/sollte.
Aber da das Framework ja nun Open Source ist, wäre es für dich und andere ja auch möglich, die Idee und den Code dazu beizusteuern. Wer weiß, evtl. findet diese Erweiterung wirklich ihren Weg in die Standardbibliotheken.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Moderator Montag, 19. Januar 2015 13:38
-
Hallo,
Du solltest noch mal darüber nachdenken...
Die Aufgabe eines Serialisierers ist weder das Filtern, Sortieren oder Verzieren mit Schleifchen... all das widerspricht den SOLID Prinzipien (SRP uam.)
Hier wäre es sinnvoller Deine Auflistungen, um Methoden zu erweitern, die eine Filterung (sei es fürs Serialisieren oder anderen Gründen) vornehmen. Die könnten z. B. ein IEnumerable<ListType> liefern.
Auf Instanz-Ebene kann wiederum eine Schnittstelle zur Verallgemeinerung dienen - siehe u. a. Stefans Antwort.
So bindest Du das Ganze nicht einen spezifischen Serialisierer - ein Tausch ist leichter möglich. Auch eine Nutzung für vergleichbare Aufgaben über die Persistenz hinaus wird dadurch möglich.
Gruß Elmar
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Moderator Montag, 19. Januar 2015 13:39
-
Hi,
XmlIgnore eher nicht, da das eine statische Angabe zur Designzeit ist und sich nicht auf einzelne, sondern eben auf alle Instanzen auswirkt. Ob ShouldSerialize den Prinzipien widerspricht, kann ich nicht sagen, könnte aber schon eher sein.
Mir ist schon klar, dass das, was Du da machen willst, nicht unbedingt ganz abwegig ist und auch ähnlich zu sehen wäre wie ShouldSerialize auf Eigenschaftsebene aber es gibt leider nunmal nichts, was das von dir Gewünschte anbieten würde. Daher wirst Du um eine eigene Logik nicht drumrum kommen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Moderator Montag, 19. Januar 2015 13:40
Alle Antworten
-
Hallo,
Der XmlSerializer selbst kennt von Haus keine Möglichkeit einzelne Instanzen auszulassen.
Das einfachste ist es, Du erstellst vor dem Serialisieren eine neue Auflistung - mit ein bissel LINQ sollte das schnell gemacht sein - und verwendest die anstatt der Basis-Auflistung.
Gruß Elmar
-
Hallo,
du hast natürlich die Möglichkeit die IXmlSerializable-Schnittstelle zu implementieren und so das (de)serialisieren komplett selbst zu übernehmen.Ich würde (wenn möglich) allerdings auch zu einer neu gefilterten Liste greifen. Das halte ich in den meisten Fällen für das Beste.
Tom Lambert - .NET (C#) MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets -
Hi,
einen XML Serialisierer, der deine Anforderung unterstützt, kenne ich nicht. Letztendlich müsste der auch ja alles mögliche können, da andere Entwickler auch andere Anforderungen haben.
Die kannst dir aber doch problemlos mittels FindAll, Select, Where, ... einen Filter bauen und dir dann eine List<T> zurückgeben lassen. Daher verstehe ich nicht, wo das Problem liegen soll.
ObservableCollection<DeineKlasse> Liste = new ObservableCollection<DeineKlasse>(); Liste.Add( new DeineKlasse() { Name = "Abc", Description = "Hallo Welt" } ); Liste.Add( new DeineKlasse() { Name = "Def", Description = "Hallo Galaxie" } ); Liste.Add( new DeineKlasse() { Name = "Xyz", Description = "Hallo Welt" } ); List<DeineKlasse> AusgabeListe = Liste.Where( f => f.Description == "Hallo Welt" ).ToList();
Damit hast Du in "AusgabeListe" 2 Elemente enthalten. Deine Originalliste bleibt erhalten. "AusgabeListe" übergibst Du dann an die Serialisierungsmethode.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
- Bearbeitet Stefan FalzModerator Mittwoch, 7. Januar 2015 15:03
-
Wünschenswert wäre gewesen sowas wie [XmlIgnore] auch zur Laufzeit für Listen machen zu können.
Das Problem ist das ich fürs Speichern und Laden eine Klasse habe, der man ein Objekt übergibt und dieses dann einfach serialisiert oder deserialisiert wird. Es steht ja im Objekt jeweils drin was gespeichert und was ignoriert werden soll, via [XmlIgnore] etc..
Das Problem bei der Lösung mit Linq ist, dass man für jeden Spezialfall in dem Konfigurator rum hampeln muss, damit nur das richtige gespeichert wird. Dies ist allerdings der falsche Ort für sowas. Wie ein Objekt gespeichert wird sollte im Objekt stehen. Ich werde daher mal schauen wie man mit dem IXmlSerializable arbeiten kann.
Ich würde gerne meinen Objekten einfach eine Eigenschaft verpassen, die vorgibt ob das Objekt gespeichert werden soll oder nicht. Siehe z.B. ShouldSerialize für Properties, eben nur für Objekte einer Liste.
-
Hi,
deine Anforderung ist aber eben recht speziell bzw. gibt es derart viele Möglichkeiten, die die User dann anwenden könnten, dass es eben sinnlos ist, sowas von Haus aus einzubauen.
Es gibt keine Standardeigenschaft dafür. Es steht dir natürlich aber frei, eine Basisklasse, Schnittstelle, ... zu erstellen, die eine solche Eigenschaft hat und die dann von deinen Methoden berücksichtigt wird.
Da die Serialisierung aber alles mögliche serialisieren/deserialisieren kann, also auch Standardklassen, Klassen von Drittanbietern, Listen von Strings, Zahlen, ... die dann verständlicherweise alle keine solchen Eigenschaft hätten, musst Du dir das selbst bauen. Und ich sehe da immer noch kein großes Hindernis, insbesondere, wenn Du eh eigene Methoden für die Serialisierung/Deserialisierung verwendest.
Du musst auch nicht für jeden "Spezialfall" an irgendeinem Konfigurator (welchen auch immer Du damit meinst) rumbasteln, sondern einfach deine Eigenschaft in alle deine Klassen einbauen und die dann auswerten. Wo soll da das Problem liegen?
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Obs jetzt was spezielles ist oder nicht, würde ich jetzt nicht wagen zu beurteilen....
Hier mal ein gist mit dem hoffentlich klar wird worum es geht: https://gist.github.com/darinkes/c0d079ca676abec1b3d5
Natürlich ist es kein großer Aufwand mittels Linq ein bisschen Filtern, aber schön ist das nicht. Schöner wäre es, wenn das Objekt immer entscheidet ob und wie es serialisiert wird.
Dachte nur, nachdem es ShouldSerialize{PropertyName}() für Properties gibt, ob es das dann nicht auf für das ganze Objekt gibt.
-
Hi,
ich persönlich würde, wenn mir das so sehr am Herzen liegt, alle Klassen von einer Schnittstelle ableiten oder eben eine Basisklasse mit dieser Eigenschaft erstellen und alle relevanten Klassen dann von dieser Klasse erben lassen. Mit einem Attribut könnte man dann auch gleich angeben, welche Eigenschaft(en) für die Steuerung der Serialisierung zuständig ist.
Es gibt verschiedene Mechanismen, mit denen man die (XML) Serialisierung steuern kann, bspw.:
Private _Age As Int64 <System.Xml.Serialization.XmlIgnoreAttribute> _ Public AgeSpecified As Boolean = False <XmlAttribute()> _ Public Property Age() As Int64 Get Return _Age End Get Set _Age = Value If Value > 0 Then AgeSpecified = True End If End Set End Property
Letztendlich kann man sich also auch selbst etwas ähnliches bauen, dass das für Objekte in einer Liste macht. Allerdings wird man sich dafür dann wohl auch einen eigenen Serialisierer erstellen müssen, da die Standardklassen das nicht kennen.
Wie gesagt, ich sehe deine Anforderung als zu speziell bzw. zu weit gefasst (wenn man die ggfs. in Frage kommenden anderen Anforderungen anderer User berücksichtigt) als dass Microsoft das von Haus aus ins .NET Framework einbauen müsste/sollte.
Aber da das Framework ja nun Open Source ist, wäre es für dich und andere ja auch möglich, die Idee und den Code dazu beizusteuern. Wer weiß, evtl. findet diese Erweiterung wirklich ihren Weg in die Standardbibliotheken.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Moderator Montag, 19. Januar 2015 13:38
-
Hallo,
Du solltest noch mal darüber nachdenken...
Die Aufgabe eines Serialisierers ist weder das Filtern, Sortieren oder Verzieren mit Schleifchen... all das widerspricht den SOLID Prinzipien (SRP uam.)
Hier wäre es sinnvoller Deine Auflistungen, um Methoden zu erweitern, die eine Filterung (sei es fürs Serialisieren oder anderen Gründen) vornehmen. Die könnten z. B. ein IEnumerable<ListType> liefern.
Auf Instanz-Ebene kann wiederum eine Schnittstelle zur Verallgemeinerung dienen - siehe u. a. Stefans Antwort.
So bindest Du das Ganze nicht einen spezifischen Serialisierer - ein Tausch ist leichter möglich. Auch eine Nutzung für vergleichbare Aufgaben über die Persistenz hinaus wird dadurch möglich.
Gruß Elmar
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Moderator Montag, 19. Januar 2015 13:39
-
Hi,
XmlIgnore eher nicht, da das eine statische Angabe zur Designzeit ist und sich nicht auf einzelne, sondern eben auf alle Instanzen auswirkt. Ob ShouldSerialize den Prinzipien widerspricht, kann ich nicht sagen, könnte aber schon eher sein.
Mir ist schon klar, dass das, was Du da machen willst, nicht unbedingt ganz abwegig ist und auch ähnlich zu sehen wäre wie ShouldSerialize auf Eigenschaftsebene aber es gibt leider nunmal nichts, was das von dir Gewünschte anbieten würde. Daher wirst Du um eine eigene Logik nicht drumrum kommen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Moderator Montag, 19. Januar 2015 13:40
-
Und was würde ich dann mit meinen XmlIgnore und ShouldSerialize() machen? Die müsste ich dann auch wegschmeißen, da der JSON Serializer wieder was anderes erwartet.
Mir ist eure Aussage schon klar und ich bedanke mich für die Bestätigung, dass es hier nichts Fertiges gibt.
-
Hallo,
Bei JSON verwendet man ein anderes Attribut (ScriptIgnore) - und es wäre insofern eine Fleiß-Aufgabe (bzw. Suchen/Ersetzen...). Entsprechendes wäre bei WCF erforderlich - dort DataMember (umgekehrt).
An der übrigen Logik würde sich nichts ändern, weil man jeweils eine neue Auflistung erzeugt - die das (fiktive) ShouldSerialize berücksichtigt.
Andersherum, es in jede Art von Serialisierer zu implementieren kostet reichlich Zeit (und Nerven) - und schließt die Nutzung von Third Party Code weitgehend aus.
Gruß Elmar
-
Genau, da stimme ich dir voll zu mit den Zeit und Nerven :)
Wobei mir der XmlSerializer in .NET bisher sehr gut gefällt und mir wenig Probleme bereitet. Da gab es schon andere Kandidaten...
Ich sehe kein Hindernis, das es ein ShouldSerialize() (ohne Property-Name) für die gesamte Instanz des Objektes geben könnte. Wenn man bedenkt, dass es das bereits für einzelne Properties gibt.
Allerdings wenn man es richtig machen will, gebe ich dir natürlich recht. Da sollte man eventuell auch ShouldSerialize() für die Properties vermeiden, denke ich.
Aber gut, gibt es nicht und damit Schluss :)
-
Hallo da_rinkes,
Wenn ein oder mehrere Beiträge Dir weitergeholfen, Aufschlüsse gegeben und Deine Frage beantwortet haben, markiere sie bitte als Antwort.
Gruß,
Dimitar
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.
- Bearbeitet Dimitar DenkovMicrosoft contingent staff, Moderator Montag, 12. Januar 2015 11:04