Laden...

Newtonsoft Json - Allgemeinen Konstruktor verwenden

Erstellt von ByteDevil vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.930 Views
ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren
Newtonsoft Json - Allgemeinen Konstruktor verwenden

verwendetes Datenbanksystem: <Json>

Hi,

ich serialisiere Daten, speichere sie in einer Datenbank und hole sie bei Bedarf heraus und deserialisiere sie wieder. Dabei wird unter Anderem eine struct mit deserialisiert, welche nicht aus meiner Feder stammt. Darin enthalten sind 3 double Werte, über die ich nur über Properties komme. Diese haben leider nur einen Getter. Die Struktur verfügt über drei Konstruktoren:


Vector3d() // macht einen 0-Vektor
Vector3d(double x, double y, double z)
Vector3d(double [] xyz)

Newtonsoft.Json verwendet natürlich den Standardkonstruktor und verwirft die Werte dann halt einfach, weil sie nicht zugewiesen werden können.

So sieht der Json-String aus:


{
      "LargestElement": 0,
      "LengthSqrd": 5.0336,
      "Length": 2.2435685859808254,
      "Z": 1,
      "Y": 1.4,
      "X": 1.44
}

Ich muss Newtonsoft nun irgenwie dazu kriegen, den zweiten oder dritten Konstruktor mit den x, y und z-Werten zu nutzen.

Ich weiß, das ich das irgendwie über einen ContractResolver lösen kann. Ich nutze auch bereits einen bei der serialisation/deserialisation, wo ich spezielle Properties setze die generell ignoriert werden sollen. Nur habe ich nichts dazu gefunden, wie ich in diesen einen ContractResolver nun eine "Anleitung" für Newtonsoft hinterlegen kann, wie es diesen blöden Vector initialisieren kann. Der Vector ist von Autodesk (AutoCAD) und den muss ich leider auch nutzen.
Auch wäre es schön, wenn ich dort noch weitere dieser "Anleitungen" für andere Typen hinterlegen kann.

Hat das jemand von euch schonmal gemacht und mag mir da helfen?

16.830 Beiträge seit 2008
vor 4 Jahren

Es gibt Klassen, die lassen sich nicht ohne weiteres direkt serialisieren - und das solltest Du auch nicht erzwingen.
Stattdessen solltest Du Dir eben Klassen gestalten, die zum Austausch dienen; quasi DTOs.

Umsetzen kannst Du das dann via JsonConverter Attributen.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Hallo Abt,

danke für die Antwort. Nun ist mir leider nicht ganz klar, wie ich einer Klasse auf die ich keinerlei Zugriff habe mit einem Attribut versehen kann. Hilfst du mir bitte auf die Sprünge?

16.830 Beiträge seit 2008
vor 4 Jahren

Wenn Du nen kurzen Blick in die Doku wirfst, dann siehst Du, dass das Attribut nicht direkt auf die Klasse gesetzt wird, sondern auf die Eigenschaft, in der Du die Klasse verwendest.

[JsonConverter(typeof(MyVector3DConverter))]
public Vector3d Vector {get;set;}
ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Achso meinst du das. Mhhh ja das geht zwar...aber ungern. Auf diese Klasse habe ich Zugriff, aber auch die ist nicht von mir und wird in einer gigantischen Software noch an (buchstäblich) hunderten weiteren Stellen genutzt. Möchte die ungern anpacken. Deshalb habe ich mir auch den bereits erwähnten ContractResolver geschrieben um einige der Properties zu ignorieren und habe nicht alles mit


[JsonIgnore]

geschmückt.

EDIT: Kann ich nicht deine Idee mit dem Converter und meine mit dem ContractResolver verheiraten? Also einen ContractResolver der diesen einen Converter nutzt, wenn er einen Vector3d vor die Flinte bekommt?

16.830 Beiträge seit 2008
vor 4 Jahren

Naja einen Tod musst sterben.

Dass jemand eine Austausch-Klasse gestaltet mit nicht-serialiserbaren Klassen war halt schon ein Grundfehler / nicht die beste Entscheidung.
Dem würde ich zuerst auf die Finger hauen 😉

Wenn Du die Klasse nicht anfassen willst, dann bleibt Dir nur der Contract Resolver.

Du meinst zwar, dass Du dazu nichts gefunden hast; wenn man jedoch nach Google-Suche nach c# json contract resolver type sucht, dann kommt man direkt zur Json Dokumentation mit Samples dazu - sogar mit DateTime direkt zu einem struct-convert.
Ansonsten versteh ich nicht, wo genau das Problem nun ist 😃

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Naja, die Klasse ist gute 20 Jahre alt^^ Daran hat damals wohl noch keiner so richtig gedacht.

Okay, ich schaue mir die Doku nochmal genau an mit dem im Hinterkopf was du gesagt hast. Melde mich wenn ich Erfolg hatte.

Dankeschön

5.658 Beiträge seit 2006
vor 4 Jahren

wie es diesen blöden Vector initialisieren kann. Der Vector ist von Autodesk (AutoCAD) und den muss ich leider auch nutzen.

Das Hauptproblem hier ist nicht der "blöde Vector" von Autodesk, sondern deine Software-Architektur. Datentypen aus einer externen API haben nichts in der DAL zu suchen.

Der richtige Weg wäre, einen eigenen Vektor-Datentyp zum Speichern zu verwenden, oder einfach die Koordinaten als drei Werte abzuspeichern. Dann werden auch keine redundanten Werte wie "Length" oder "LengthSqrd" mitgespeichert. Die Autodesk-Datentypen werden erst dann initialisiert, wenn die API verwendet wird.

Eine andere Möglichkeit wäre, die API zu verwenden, um deren Datentypen zu serialisieren, oder bspw. eine AutoCAD-Datei zu erstellen, und diese dann in der DB abzulegen.

Siehe dazu auch [Artikel] Drei-Schichten-Architektur

Weeks of programming can save you hours of planning

T
2.223 Beiträge seit 2008
vor 4 Jahren

Genau das sagte auch Abt schon in seinem ersten Beitrag mit den DTOs.
Man sollte eben die Typen von anderen Libs nur dort verwenden, wo diese auch benötigt werden und nicht mehr.

Wenn man zu sehr auf die externen Datentypen aufbaut, kann es schon bei einem Update der Libs/API an zich Stellen zu Fehlern kommen, wenn sich die Datentypen ändern oder gar komplett entfernt werden.

Gerade externe Anbindungen sollten immer sauber gekapselt werden um nicht in Versuchung zu kommen, diese im eigenen Code übermäßig zu verwenden.

Hier sollte man immer auf eigene Typen in seinem Code aufbauen und nur an den Stellen, wo man gegen die entsprechenden Lib/API arbeitet, auch die benötigten Typen anlegen und aus den eigenen Typen befüllen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

3.003 Beiträge seit 2006
vor 4 Jahren

Du kannst den JsonConverter auch direkt beim (de)serialisieren übergeben. Dafür muss keine beteiligte Klasse angefasst werden.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)