1

Ich finde mich ein wenig verloren auf diesem. Ich kann ehrlich gesagt den Fehler nicht sehen, wenn nur eine Klassenstruktur nicht mit JSON-Fehlern übereinstimmt. Aber ich bezweifle es, da es genau dieselbe Klassenstruktur ist, die ich zum Erstellen des JSON verwende.Json.Net Klassenhierarchie mit ObservableCollection und INotifyPropertyChange wird serialisiert, aber nicht deserialisiert

Wenn mir jemand in die richtige Richtung zeigen kann, wäre ich sehr dankbar.

Ich habe eine Dotnetfiddle erstellt, um zu vermeiden, die Frage mit riesigen Stücken Code zu erfassen. Hier ist der Link: Fiddle

Ich generiere das JSON mit einer Konsolenanwendung, die Informationen über das DB-Schema erhält. Ich verwende ein gemeinsames Projekt mit allen darin definierten Entitäten, um die Daten in den Speicher zu laden und dann den JSON von dieser Struktur zu generieren. Dann benutze ich dasselbe Projekt mit denselben Entitäten in einer anderen Anwendung, um ein anderes DB-Schema mit dem JSON-Protokoll zu vergleichen. Diese Anwendung kann das JSON nicht deserialisieren. Versucht, ein minimales Beispiel mit einer einzelnen Klasse zu liefern und wie Sie auf der Geige sehen können ... das deserialisiert auch nicht. Es ist mein Verständnis, dass ObservableCollections in der Tat ohne Probleme serialisieren und deserialisieren sollte, und dass INotifyPropertyChange keine Probleme verursachen sollte (solange Sie nicht versuchen, ein Ereignis mit einer Nullreferenz auszulösen). Also ... hat irgendjemand eine Idee, was hier vor sich geht?

EDIT: Vergessen zu erwähnen. Beachten Sie, dass nur die Basistyp-Zeichenfolge deserialisiert wird ... daher wird eine Deserialisierung ausgeführt, nur keine Klassen wie ObservableCollection oder Benutzerklassen. Vielleicht hilft das irgendwie, das Problem zu lokalisieren.

EDIT2: Es wurde ein Trace-Writer und die JSON.Net Spur ist die richtige Art für die Erkennung von Objekten, so dass ich das Problem zu erraten ist Arten auf Umwandlung oder einige der Arten

Antwort

1

Das Problem bei der Initialisierung ist wie Ihre Property-Getter mit der Standardeinstellung ObjectCreationHandling in Json.Net kombiniert werden. Erlauben Sie mir Folgendes zu erklären:

Wenn eine Referenzeigenschaft während der Deserialisierung einen vorhandenen Wert ungleich null hat, versucht Json.Net, die vorhandene Instanz wiederzuverwenden und zu füllen, anstatt eine neue Instanz zu erstellen. Um herauszufinden, ob die Eigenschaft einen Wert hat, ruft Json.Net den Getter auf. In Ihrem Fall ist, kehrt der Getter eine neue Instanz, wenn das dahinter liegende Feld null ist, aber kritisch, ist es nicht das dahinter liegende Feld auf die neue Instanz festgelegt:

get { return _header ?? new StoredProcedureDataHeader(); } 

Json.Net auffüllt dann die neue Instanz. Da das Hintergrundfeld nie auf die neue Instanz gesetzt wurde, wird diese Instanz letztendlich verworfen. Json.Net ruft niemals Ihren Setter auf, da angenommen wird, dass Ihr Objekt bereits einen Verweis auf die neue Instanz hat, da es diese Instanz vom Getter erhalten hat. Wenn Sie dann nach der Deserialisierung das nächste Getter aufrufen, erhalten Sie eine neue leere Instanz statt der erwarteten.

Es gibt zwei Möglichkeiten, das Problem zu beheben:

  1. Ihre Getter Ändern Sie das dahinter liegende Feld zu setzen, wenn eine neue Instanz erstellt wird, zum Beispiel:

    get 
    { 
        if (_header == null) 
        { 
         _header = new StoredProcedureDataHeader(); 
        } 
        return _header; 
    } 
    

OR

  1. Ändern Sie die ObjectCreationHandling Einstellung auf Replace, um Json zu zwingen.Net, um beim Deserialisieren immer neue Instanzen zu erstellen. Json.Net wird dann den Setter und nicht den Getter aufrufen, was ich denke was du willst.

    var settings = new JsonSerializerSettings 
    { 
        ObjectCreationHandling = ObjectCreationHandling.Replace 
    }; 
    
    var data = JsonConvert.DeserializeObject<StoredProcedureData>(json, settings); 
    

In Ihrem Fall würde ich wirklich empfehlen, dass Sie beiden Fixes anwenden. Wenn Sie Ihre Getter nicht reparieren (Option 1), könnten Sie an anderer Stelle in Ihrem Code auf ein ähnliches Problem stoßen. Sie könnten beispielsweise Folgendes haben:

Erraten Sie, welcher Wert gedruckt wird?

Und Option 2 schützt vor möglicherweise unerwarteten Ergebnissen, wenn Sie eine Sammlung irgendwo initialisiert haben, um einen Standardsatz von Werten zu haben. Zum Beispiel hatte, wenn Sie so etwas wie dieses:

public StoredProcedureData() 
{ 
    _funcRef = new ObservableCollection<string>(); 
    _funcRef.Add("Initialize"); 
} 

dann, wenn Sie deserialisieren, werden Sie die Standardwerte Plus die Werte aus dem JSON erhalten, die wahrscheinlich nicht das, was Sie wollen. Die Einstellung ObjectCreationHandling auf Replace stellt sicher, dass Sie nur die Werte erhalten, die aus JSON deserialisiert wurden.

+0

Vielen Dank für die Erklärung. Ich habe beide Korrekturen angewendet. Ich war so auf das JSON-Format konzentriert, dass ich mir diese verwaiste Instanz, die ich erstellt habe, nie angesehen habe. Irgendwie peinlich. –

+0

Keine Sorgen. Ich bin froh, dass ich helfen konnte. –

Verwandte Themen