Autor Beitrag
Bodo
Hält's aus hier
Beiträge: 5



BeitragVerfasst: Di 19.01.10 22:36 
Halloo...

Ich habe ein kleines Problem wenn ich die Objekte meines kleinen Progrämmchens serialisieren will.

Das ganze Programm zu posten würde absolut den Rahmen sprengen, daher versuch ich das ganze ein wenig abstrakter zu erklären:

Ich habe eine Liste von Objekten A, seien A mal Verschiedene Lenkradsorten.
Des weiteren habe ich ein Objekt B, sei B mal ein Auto, dieses Auto hat eines der Lenkradsorten aus der Liste von Objekten A.

Bedeutet:

Die Linkradliste zeigt unter anderem auf eine bestimmte Lenkradsorte.
Das Auto-Objekt B zeigt nun auf das selbige Lenkrad.

Ändere ich im Debugger an dieser Stelle einen Wert der Lenkradsorte des Autos, ändert sich natürlich auch der Wert der Lenkradsorte aus der Liste (gleiche Speicheradresse, nur zwei Pointer die halt drauf zeigen, ich denke bis hierhin sollte noch alles verständlich sein^^).


Jetzt Serialisiere ich das Ganze:

Beide Klassen implementieren das Interface ISerializable.
In der Klasse Lenkradsorte werden nur String und double Werte gespeichert.
Ich Serialisiere also die Lenkradsortenliste und jede Lenkradsorte wird so gespeichert wie sie soll.

In der Klasse Auto wird aber unter anderem auch das Objekt der Klasse Lenkradsorte Serialisiert.
Statt aber eine Referenz zu bilden wird eher eine Kopie des Objektes erstellt (hab ich zumindest das Gefühl)...


Wenn ich nun nach dem Deserialisieren einen Wert des Auto->Lenkrads ändere ändert sich das dazugehörige Objekt innerhalb der Liste nicht mehr, sprich es gibt nun zwei Lenkradsorten, eine in der Liste, eine beim Auto, die beiden sollten aber bitte die gleiche Speicheradresse haben..


Zum De-/Serialisieren benutze ich einen BinaryFormatter und einen FileStream.
In den beiden Klassen implementiere ich wie schon gesagt die ISerializable-Schnittstelle und die dazugehöriegen Methoden
public void GetObjectData(SerializationInfo info, StreamingContext context)
und den Konstruktor...



Wenn jemand hierzu eine Lösung hat wär ich ihm sehr dankbar, ich ver-/suche schon seit 5 Stunden aber finde rein gar nix...

Danke im voraus.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 20.01.10 00:02 
:welcome:

Der BinaryFormatter behält normalerweise Referenzen bei:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
    [Serializable]
    class Node
    {
      public Node Left { get; set; }
      public Node Right { get; set; }
    }

    static void Main(string[] args)
    {
      var n = new Node();

      var graph = new Node { Left = n, Right = n };

      using (var stream = new MemoryStream())
      {
        new BinaryFormatter().Serialize(stream, graph);
        stream.Seek(0, SeekOrigin.Begin);
        var graph2 = (Node)new BinaryFormatter().Deserialize(stream);
        Debug.Assert(graph2.Left == graph2.Right);
      }
    }

Du scheinst irgendwo die referenzielle Gleichheit selbst zu zerstören.

_________________
>λ=
Bodo Threadstarter
Hält's aus hier
Beiträge: 5



BeitragVerfasst: Mi 20.01.10 01:31 
Danke für die schnelle Antwort und für die Willkommensgrüße^^

Ich habs jetzt 100 mal durchgeschaut, ich habe auch die methode GetObjectData aus den beiden Klassen rausgenommen, sie werden also standard gemäß serialisiert.

Ich habe das Gefühl ich werde irgendwie noch die Schnittstellen ObjectManager und SerializationObjectManager implementieren müssen, weil sich diese wohl speziell um Referenzen kümmern, allerdings habe ich überhaupt keine Ahnung wie das auszusehen hat... Wenn da jemand ein Anwendungsbeispiel hat wär ich ihm sehr verbunden. Ich komm hinter die Logik da nich hinter..

Dankeschön
Bodo Threadstarter
Hält's aus hier
Beiträge: 5



BeitragVerfasst: Mi 20.01.10 20:24 
Huhu,

habs dann doch noch geschafft, falls jemand irgendwann mal vor dem gleichen Problem steht, hier die Lösung:


Bei der Deserialisierung muss man sich auf eine besondere Weise organisieren.
Die Klasse Lenkradsorte (siehe oben) implementiert nun zusätzlich IObjectReference. In der Methode die davon geerbt wird (GetRealObject) wird nun geprüft ob ein "gleiches" (nicht gleiche Speicheradresse, also == sondern ein sich gleichendes .Equals() ) Objekt bereits vorhanden ist da doppelungen nicht gewollt sind.
Wenn ja wird an dieser Stelle dieses Objekt einfach zurückgegeben, wenn nein wird es der Liste hinzugefügt und dann selbst zurückgegeben.


Hat lange gedauert bis ich darauf gekommen bin, bzw das Interface gefunden habe.


mfg
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 20.01.10 20:28 
Gut zu hören :D .

Warum es aber bei dir nicht von Haus aus funktioniert, ist mir noch nicht klar. Ich habe in mein Beispiel oben auch mal ISerializable eingebaut gehabt, gleiches Ergebnis.

_________________
>λ=
Bodo Threadstarter
Hält's aus hier
Beiträge: 5



BeitragVerfasst: Mi 20.01.10 21:39 
Hey Kha,

Ich hab mal mein Szenario etwas primitiver als in echt dargestellt und an dein Beispiel angelehnt, Ich habe es so ausgeführt und anhand der Kommentare an den Debug.Assert befehlen kannst erkennen, was passiert ist.

Hier mein Beispiel, was sich ein wenig von deinem Unterscheidet:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Warenwirtschaft2.Waren
{
    [Serializable]
    public class Node
    {

        static void Main()
        {
            Node a = new Node();        //Das Lenkrad woraus nachher zwei Lenkräder werden

            Node[] graph = new Node[2];  //Die Lenkradliste
            graph[0] = a;        //Position 0 spiegelt das Lenkrad in der Liste wieder
            graph[1] = a;        //Position 1 das Lenkrad des Autos

            Debug.Assert(graph[0] == graph[1], "Ungleich");     //true passt soweit

            //Serialisieren
            FileStream fs = new FileStream("test.data", FileMode.Create);
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, graph[0]);     //Erst wird die Liste serialisiert
            bf.Serialize(fs, graph[1]);     //Getrennt davon wird das Auto serialisiert
            fs.Close();

            //Deserialisieren
            a = graph[0] = graph[1] = null;

            fs = new FileStream("test.data", FileMode.Open);
            fs.Position = 0;
            graph[0] = (Node)bf.Deserialize(fs);        //Deserialisiere die Liste
            graph[1] = (Node)bf.Deserialize(fs);        //Deserialisiere das Auto

            Debug.Assert(graph[0] == graph[1], "Ungleich");    //FALSE --> sind nun zwei getrennte Objekte
            fs.Close();
        }
    }
}


Ich denke man erkennt die Unterschiede und eventuell daran auch, warum das nich ganz so läuft^^

mfg
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 20.01.10 23:41 
So kann das natürlich nicht funktionieren ;) . Beim Deserialisieren können Referenzen nur richtig wiederhergestellt werden, wenn alle Objekte gemeinsam serialisiert wurden. Was eigentlich auch immer machbar sein sollte, im Zweifelsfall haust du alles einfach in ein Aggregat-Objekt.

_________________
>λ=
Bodo Threadstarter
Hält's aus hier
Beiträge: 5



BeitragVerfasst: Do 21.01.10 08:59 
Tatsache...

Das war der Tipp, den ich gebraucht hab =)

Hab alles vorm Serialisieren in ein Objekt gepackt, zumindest die 5 Sammelobjekte und dieses eine Objekt dann serialisiert.

Dann deserialisiere ich dieses Objekt und hol mir da meine 5 Sammelobjekte wieder raus..

Und siehe da: alle Referenzen sind wiederhergestellt..

Danke für den Tipp ;)


mfg