Serialisierung zweier Klassen

  • C#
  • .NET (FX) 4.0

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Higlav.

    Serialisierung zweier Klassen

    Hey Leute,

    ich habe hier zwei Klassen, nennen wir sie CTO und ATO.
    Beide sind eine Anhäufung von Properties,ATO erbt von CTO.
    Beide Klassen sind als [Serializable] markiert.

    Nehmen wir nun an, ich erstelle ein Objekt vom Typ ATO und befülle alle Properties, also auch die Geerbten, und übergebe es jedoch nun einer Methode, die ein CTO-Objekt erwartet.
    Diese Methode benutzt den BinaryFormatter um aus dem CTO-Objekt ein byte[] zu machen, dass dann seinen Weg übers Internet antritt.
    Der Empfänger hat eine Methode die das byte[] zu einem CTO deserialisiert.

    Die Frage ist, hat der BinaryFormatter nur den CTO-Teil Serialisiert, oder könnte ich nun das Empfangene CTO-Objekt auf ATO casten und hätte alle Daten vorhanden?

    Dass der Empfänger nur auf CTO deserialisieren darf hat einen Grund, der nicht weiter wichtig ist. Testen kann ich es leider im Moment nicht.
    Hallo Earan,

    Habe es gerade eben getestet und zu meinem Erstaunen geht es tatsächlich. 8|
    Ich habe zuerst die Instanz des abgeleiteten Types als Basistyp behandelt und auch mit dieser Anweisung serialisiert. Beim Deserialisieren und anschliessenden Casten zum abgeleiteten Typ waren die "neuen" Properties des abgeleiteten Typs tatsächlich in der Instanz erhalten. :thumbup:

    Grüsse,

    Higlav

    EaranMaleasi schrieb:

    könnte ich nun das Empfangene CTO-Objekt auf ATO casten und hätte alle Daten vorhanden?
    Nein.
    @Higlav Auch getestet:
    Spoiler anzeigen

    C#-Quellcode

    1. private void button2_Click(object sender, EventArgs e)
    2. {
    3. System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    4. CTO instanz;
    5. CTO instanz2;
    6. ATO instanz3;
    7. // lesen
    8. using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Open))
    9. {
    10. instanz = (CTO)bf.Deserialize(fs);
    11. }
    12. using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Open))
    13. {
    14. instanz2 = (ATO)bf.Deserialize(fs);
    15. }
    16. using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Open))
    17. {
    18. instanz3 = (ATO)bf.Deserialize(fs);
    19. }
    20. MessageBox.Show("Haltepunkt");
    21. }
    Nur instanz3 hat alle ATO-Daten.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Auch getestet:

    VB.NET-Quellcode

    1. <Serializable> _
    2. Class A
    3. Public Property Text As String = "A"
    4. End Class
    5. <Serializable> _
    6. Class B : Inherits a
    7. Public Property Text2 As String = "B"
    8. End Class
    9. Private Sub test()
    10. Dim b = New B
    11. Dim bf = New BinaryFormatter
    12. Dim a As A = b
    13. Using ms As New MemoryStream
    14. bf.Serialize(ms, a)
    15. ms.Seek(0, SeekOrigin.Begin)
    16. Dim bb = DirectCast(bf.Deserialize(ms), B)
    17. End Using
    18. End Sub
    null Problemo!
    Interessanterweise ist das nicht nur beim Serialisieren so, sondern im gesamten Framework.
    konnte es nun endlich selbst testen.
    Selbst solches Konstrukt,

    C#-Quellcode

    1. ATO ato = new ATO()
    2. {
    3. ATOprop1= true, //nicht in CTO enthalten
    4. ATOprop2= true, //nicht in CTO enthalten
    5. ATOprop3= 12345, //nicht in CTO enthalten
    6. };
    7. CTO cto = ato;
    8. ATO ato2 = (ATO)cto;
    9. button1.Text = string.Format("{0}-{1}-{2}",ato2.ATOprop3, ato2.ATOprop2, ato2.ATOprop1);

    funktioniert einwandfrei, der Button hat den Text 12345-True-True.

    Ich hatte irgendwie erwartet, dass die "überflüssigen" Properties und ihre Werte verloren gehen, dennoch "erinnert" sich das Framework an alles :D
    Das ist polymorphie.
    Das Framework erinnert sich nicht, sondern wenn ein Objekt ein ATO ist, dann ists ein ATO.
    Das kannste dann (polymorph) an eine CTO-Variable zuweisen, aber davon wird das ATO kein CTO, sondern bleibt ein ATO.

    Nur die ATO-spezifischen Properties sind der CTO - Variable zunächstmal nicht bekannt, könnten aber durch Casting wieder sichtbar gemacht werden.

    Casting ist aber immer ein Unsicherheitsfaktor, denn prinzipiell könnte es ja auch eine Klasse BTO geben, auch von CTO erbend, und ein BTO könnte ebensogut an die Var zugewiesen werden. Und das BTO kannste dann natürlich nicht auf ATO casten, weils ist nunmal ein BTO.

    Klar soweit?
    Wozu sollte das gut sein?
    Wenn ein Ato in einer Cto-Variable ist, dann stellt es nur seine Cto-Eigenschaften direkt zur Verfügung.
    Klar kann man es auf Ato casten, und dann auch weiteres abrufen, aber das liegt in der Verantwortung des Cto-Benutzers, nicht dessen, der das Cto als Cto bereitstellt.
    Ja, man kann auch ein neues Objekt creiern, aber dann hat man 2 Objekte, was evtl. für mehr Verwirrung sorgt als für Klarheit.
    ZB ist das neue Objekt nicht mehr identisch mit dem Original, und das kann sich auch unerwartet auswirken, etc..

    @WhitePage: auf Cto braucht man nicht casten, denn ein Ato ist ja bereits ein Cto.

    ErfinderDesRades schrieb:

    Klar kann man es auf Ato casten, und dann auch weiteres abrufen, aber das liegt in der Verantwortung des Cto-Benutzers, nicht dessen, der das Cto als Cto bereitstellt.

    In Meinem Falle schon. Es Muss verhindert werden, dass die ATO Daten durch casten abrufbar sind. Ich muss sie quasi entsorgen.
    Wäre es in dem Falle nicht einfacher, wenn du das CTO-Objekt als Property mitgeben würdest?
    Ansonsten könntest du eine Methode schreiben, die über Reflection(oder gleich direkt, je nach dem) alles ATO-typische nullt.