Serialisierung: Unterschied zwischen den Versionen
Aus Das Sopra Wiki
Keine Bearbeitungszusammenfassung |
LeonH (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| (20 dazwischenliegende Versionen von 7 Benutzern werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
{{review}} | |||
{{löschen}} | |||
{{Navi:Implementierung}} | {{Navi:Implementierung}} | ||
Serialisierung<ref name="RunTimeRerial">http://msdn.microsoft.com/en-us/magazine/cc301761.aspx Jeffrey Richter: Run-time Serialization</ref> bezeichnet den Vorgang, ein [ | Serialisierung<ref name="RunTimeRerial">http://msdn.microsoft.com/en-us/magazine/cc301761.aspx Jeffrey Richter: Run-time Serialization</ref> bezeichnet den Vorgang, ein [https://docs.microsoft.com/de-de/dotnet/api/system.object?view=netcore-3.1 Objekt] in einen Datenstrom umzuwandeln. Dieser kann dann als auf einer Festplatte gespeichert oder über ein Netzwerk übertragen werden. C# stellt dafür Klassen bereit. | ||
== | == Formate == | ||
Es gibt mehrere Möglichkeiten, ein Objekt zu serialisieren | Es gibt mehrere Möglichkeiten, ein Objekt zu serialisieren: | ||
; Binary Serialization | ; Binary Serialization | ||
: Das Objekt wird in einem Binärformat gespeichert. Es kann nur von [[.NET]] gelesen werden. | : Das Objekt wird in einem Binärformat gespeichert. Es kann nur von [[.NET]] gelesen werden. | ||
; XML Serialization | ; XML Serialization | ||
: Das Objekt wird in ein XML-Format serialisiert. Es kann dadurch relativ einfach auch auf anderen Plattformen gelesen werden. | : Das Objekt wird in ein XML-Format serialisiert. Es kann dadurch relativ einfach auch auf anderen Plattformen gelesen werden. Ausserdem kann man die Dateien als Mensch intuitiv verstehen und sogar editieren. | ||
; SOAP | ; SOAP | ||
: Stadardisiertes Verfahren um Objekte zu serialisieren. Dadurch extrem einfach für andere Plattformen aber auch etwas schwerer für den Menschen zu lesen. | : Stadardisiertes Verfahren um Objekte zu serialisieren. Dadurch extrem einfach für andere Plattformen aber auch etwas schwerer für den Menschen zu lesen. | ||
== | == Was kann Serialisiert werden == | ||
Um Ein Objekt zu serialisieren braucht es extrem wenig Code. Man sollte allerdings beachten, daß nur sinnvolle Daten serialisiert werden. Instanzen der Klasse <tt>File</tt> können | Um Ein Objekt zu serialisieren braucht es extrem wenig Code. Man sollte allerdings beachten, daß nur sinnvolle Daten serialisiert werden. Instanzen der Klasse <tt>File</tt> können zum Beispiel nicht serialisiert werden. Der Grund ist, dass deren Inhalte nicht im Hauptspeicher liegen. Ebenfalls können einige XNA-Klassen nicht serialisiert werden, z.B. die <tt>Model</tt>-Klasse, weil Teile davon im Grafikkartenspeicher oder anderen Orten liegen. Wenn man nicht sicher ist, kann man sich mit F12 (oder Rechtsklick -> Go to Defninition) zum Code wechseln(oder zu den Metadaten). Und an den [[Serialisierung#Attribute|Attributen]] erkennen, ob sie serialisierbar sind und welche Felder ausgeschlossen werden. | ||
Der XmlSerializer hat weitere Einschränkungen: | |||
* Eine Klasse die Xml-serialisiert werden soll, braucht einen parameterlosen Konstrukor. | |||
* keine Zweidimensionale Arrays | |||
* (Die Klasse <tt>Dictionary</tt> und einige andere Klassen, von denen man es eigentlich nicht denkt, sind nicht erlaubt) | |||
== Attribute == | |||
Klassen und Felder können [[Attribut|Attribute]] erhalten, ob sie serialisert werden sollen oder nicht. Wenn sie serialisiert werden sollen erhalten sie folgendes Attribut: | |||
<source lang="csharp"> | <source lang="csharp"> | ||
[Serializable] | [Serializable] | ||
</source> | </source> | ||
In der Standardeinstellung werden alle Felder und [[Property|Properties]] dieser Klasse serialisiert, auch die [[Sichtbarkeit|privaten]]. Um das zu verhindern kann man diese mit | In der Standardeinstellung werden alle Felder und [[Property|Properties]] dieser Klasse serialisiert, auch die [[Sichtbarkeit|privaten]]. Um das zu verhindern kann man diese mit folgendem Attribut markieren: | ||
<source lang="csharp"> | <source lang="csharp"> | ||
[NonSerialized] | [NonSerialized] | ||
</source> | </source> | ||
Man muss allerdings beachten, daß <tt>XmlSerializer</tt> keine privaten Felder und keine private Properties serialisiert, sondern nur, was als public markiert ist. | |||
Ein kleines Beispiel: | |||
<source lang="csharp"> | |||
[Serializable] | |||
public class GameUnit | |||
{ | |||
public int hitPoints; | |||
public Vector3 position; | |||
private UnitAi unitAi; | |||
[NonSerialized] | |||
public Model unitModel; | |||
} | |||
[Serializable] | |||
public class UnitAi | |||
{ | |||
public StateMachineState state; | |||
private int abc; | |||
} | |||
</source> | |||
Wenn eine Instanz dieser Klasse serialisiert und gespeichert wird, werden folgende Daten gespeichert: | |||
* Beim BinaryFormatter | |||
** Der Integer <tt>hitPoints</tt> | |||
** Das Strukt <tt>position</tt> mit seinen Feldern | |||
** Die Referenz <tt>unitAi</tt> und die Instanz auf die sie zeigt. Und entsprechend dann auch deren Felder <tt>state</tt> und <tt>abc</tt>. | |||
* Beim XmlSerializer | |||
** Der Integer <tt>hitPoints</tt> | |||
** Das Strukt <tt>position</tt> mit seinen Feldern | |||
** Die Referenz <tt>unitAi</tt> wird nicht serialisiert, da sie als private deklariert ist [[Kategorie:Code-Beispiele]] | |||
== Referenzen == | |||
Referenzen werden in XMlSerializer und BinaryFormatter ein bisschen unterschiedlich behandelt. Da es in Xml keine Referenzen gibt, werden an derer Stelle einfach die Objekte eingeschachtelt. Während der BinaryFormatter dafür sorgt, dass nach dem Deserialisieren wieder alles so ist, wie vor dem Serialisieren. Es kann vorkommen, dass es im ganzen Serialisierungsvorgang eine Instanz mehrfach referenziert wird. Diese Instanz wird vom BinaryFormatter nur einmal serialisiert und beim Deserialisieren werden alle Referenzen wieder hergestellt. Auf diese Weise kann man eine komplette Objekthierarchie speichern. Nach dem Xml-Serialisierung und -Deserialisieren hat man jedoch für jede Referenz eine eigene Instanz, damit muss man vorsichtig sein. | |||
== | == BinaryFormatter == | ||
Man binde folgendes ein: | |||
<source lang="csharp"> | |||
using System.IO; | |||
using System.Runtime.Serialization.Formatters.Binary; | |||
</source> | |||
Zum Speichern einer Instanz wird folgender Code verwendet: | |||
<source lang="csharp"> | <source lang="csharp"> | ||
System.IO.FileStream fs = | void SaveUnit(GameUnit gameUnit, String path) | ||
System. | { | ||
FileStream fs = null; | |||
try | |||
{ | |||
fs = new FileStream(path, System.IO.FileMode.Create); | |||
BinaryFormatter bf = new BinaryFormatter(); | |||
bf.Serialize(fs, gameUnit); | |||
} | |||
catch (Exception e) | |||
{ | |||
// TODO: Fehlerbehandlung hier | |||
} | |||
finally | |||
{ | |||
// Immer den Stream schliessen | |||
if (fs != null) | |||
{ | |||
fs.Close(); | |||
} | |||
} | |||
} | |||
</source> | |||
Zum Laden einer Instanz wird folgender Code verwendet: | |||
<source lang="csharp"> | |||
GameUnit LoadUnit(String path) | |||
{ | |||
FileStream fs = null; | |||
try | |||
{ | |||
fs = new FileStream(path, FileMode.Open); | |||
BinaryFormatter bf = new BinaryFormatter(); | |||
return (GameUnit)bf.Deserialize(fs); | |||
} | |||
catch (Exception e) | |||
{ | |||
// TODO: Fehlerbehandlung hier | |||
return null; | |||
} | |||
finally | |||
{ | |||
if (fs != null) | |||
{ | |||
fs.Close(); | |||
} | |||
} | |||
} | |||
</source> | |||
== XmlSerializer == | |||
Man binde folgendes ein: | |||
<source lang="csharp"> | |||
using System.IO; | |||
using System.Xml.Serialization; | |||
</source> | |||
Um ein Objekt dann in eine Xml-Datei zu speichern führt man folgenden Code aus: | |||
<source lang="csharp"> | |||
void SaveUnit(GameUnit gameUnit, String path) | |||
{ | |||
FileStream fs = null; | |||
try | |||
{ | |||
fs = new FileStream(path, System.IO.FileMode.Create); | |||
XmlSerializer seri = new XmlSerializer(typeof(GameUnit)); | |||
seri.Serialize(fs, gameUnit); | |||
} | |||
catch (Exception e) | |||
{ | |||
// TODO: Fehlerbehandlung hier | |||
} | |||
finally | |||
{ | |||
// Immer den Stream schliessen | |||
if (fs != null) | |||
{ | |||
fs.Close(); | |||
} | |||
} | |||
} | |||
</source> | </source> | ||
Um das Objekt wieder einzulesen benutzt man folgende Zeilen: | Um das Objekt wieder einzulesen benutzt man folgende Zeilen: | ||
<source lang="csharp"> | <source lang="csharp"> | ||
GameUnit LoadUnit(String path) | |||
{ | |||
FileStream fs = null; | |||
try | |||
{ | |||
fs = new FileStream(path, FileMode.Open); | |||
XmlSerializer seri = new XmlSerializer(typeof(GameUnit)); | |||
return (GameUnit)seri.Deserialize(fs); | |||
} | |||
catch (Exception e) | |||
{ | |||
// TODO: Fehlerbehandlung hier | |||
return null; | |||
} | |||
finally | |||
{ | |||
if (fs != null) | |||
{ | |||
fs.Close(); | |||
} | |||
} | |||
} | |||
</source> | </source> | ||
Man muss dabei beachten, daß die Klasse <tt>BinaryFormatter</tt><ref name="BinFormatter">http://msdn.microsoft.com/de-de/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx MSDN-Artikel zur Klasse BinaryFormatter</ref> wesentlich mehr kann als die Klasse <tt>XmlSerializer</tt><ref name=XmlSrielizer">http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx MSDN-Artikel zur Klasse XmlSerializer</ref>, die dafür auch auf der [[XBox 360]] zur Verfügung steht. | |||
Man muss dabei beachten, daß die Klasse <tt>BinaryFormatter</tt><ref name="BinFormatter">http://msdn.microsoft.com/de-de/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx MSDN-Artikel zur Klasse BinaryFormatter</ref> wesentlich mehr kann als die Klasse <tt>XmlSerializer</tt><ref name=XmlSrielizer">http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx MSDN-Artikel zur Klasse XmlSerializer</ref>, die dafür auch auf der [[XBox 360]] zur Verfügung steht. [[Kategorie:Code-Beispiele]] | |||
== Netzwerk == | == Netzwerk == | ||
{{BA|Greitschus|Das böse böse Netzwerk. Sollten wir das hier in so einem "guten Licht" dastehen lassen, wenn man's selbst schreibt, oder sollte man den Satz evtl vorsichtiger formulieren?}} | |||
Man kann mit Serialisierung auch Daten über ein Netzwerk schicken. Das Prinzip ist das gleiche, da die Formatter auf Streams arbeiten. Was für einen Stream man nimmt ist ihnen egal. Für Netzwerkfunktionalität bieten sich entweder die speziellen [[XNA]]-Klassen dafür an, oder man schreibt die Funktionalität selbst. Dies ist flexibler und man braucht keinen [[XBox 360|XBox-Live]]-Account. Dafür funktioniert sie auf der XBox nicht. | Man kann mit Serialisierung auch Daten über ein Netzwerk schicken. Das Prinzip ist das gleiche, da die Formatter auf Streams arbeiten. Was für einen Stream man nimmt ist ihnen egal. Für Netzwerkfunktionalität bieten sich entweder die speziellen [[XNA]]-Klassen dafür an, oder man schreibt die Funktionalität selbst. Dies ist flexibler und man braucht keinen [[XBox 360|XBox-Live]]-Account. Dafür funktioniert sie auf der XBox nicht. | ||
Die nötigen Klassen finden sich im [[ | Die nötigen Klassen finden sich im [[Namensraum]] | ||
System.Net.Sockets | System.Net.Sockets | ||
| Zeile 70: | Zeile 211: | ||
} | } | ||
Console.ReadLine(); | Console.ReadLine(); | ||
</source> | </source> [[Kategorie:Code-Beispiele]] | ||
== XML == | == XML == | ||
| Zeile 78: | Zeile 219: | ||
* Leistungsfähiger als die beiden oben ist der SoapFormatter | * Leistungsfähiger als die beiden oben ist der SoapFormatter | ||
{{BA|Vogty|hier befand sich noch ein Abschnitt "Video Tutorial" bestehend aus einer Verlinkung auf ein MSDN Video, dieses existiert aber nicht mehr, ich habe den Abschnitt entfernt}} | |||
== Referenzen == | == Referenzen == | ||
<references /> | <references /> | ||
[[Kategorie:CSharp]][[Kategorie:Code-Beispiele]][[Kategorie:Begriffe]][[Kategorie:VideoTutorials]][[Kategorie:Tutorials]]</noinclude> | [[Kategorie:CSharp]][[Kategorie:Code-Beispiele]][[Kategorie:Begriffe]][[Kategorie:VideoTutorials]][[Kategorie:Tutorials]]</noinclude> | ||
[[Kategorie:MS02]] | |||
[[Kategorie:MS03]] | |||
[[Kategorie:MS04]] | |||
