Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

JsonConvert.DeserializeObject mit <List<Type>> nicht möglich. Alternativen?
1337-Cat
myCSharp.de - Member



Dabei seit:
Beiträge: 7
Herkunft: #Neuland

Themenstarter:

JsonConvert.DeserializeObject mit <List<Type>> nicht möglich. Alternativen?

beantworten | zitieren | melden

Hallo,

ich hatte eine Klasse mit Getter und Setter erstellt und konnte einen JSON-String problemlos in eine Liste des Typs parsen.

List<MyClass> t = JsonConvert.DeserializeObject<List<MyClass>>(JSONstr);
.

Nun wollte ich die Methode kompatible zu mehreren Klassen machen. Versucht habe ich

var x = Type.GetType(tableType.GetType().ToString()); //tableType ist vom typ Type und teilt mit, in welche art von List<> der JSON-String geparst werden soll
List<Type> t = JsonConvert.DeserializeObject<List<Type>>(JSONstr);

Bekomme aber folgende Fehlermeldung:
Fehler
Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Type' because the type requires a JSON string value to deserialize correctly.
To fix this error either change the JSON to a JSON string value or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.

Also kommt es nicht so ganz mit dem Typ List<Type> klar.
private Nachricht | Beiträge des Benutzers
BhaaL
myCSharp.de - Member

Avatar #erP6yAFiewXrJTqrvg6R.jpg


Dabei seit:
Beiträge: 648

beantworten | zitieren | melden

Type ist auch ein Typ vom Framework, und nicht dein konkreter Typ. Vermutlich willst du eher eine generische Methode, wo tableType als Typ-Parameter reinkommt und du am Ende JsonConvert.DeserializeObject<List<TTable>>(JSONstr) machen kannst.
private Nachricht | Beiträge des Benutzers
1337-Cat
myCSharp.de - Member



Dabei seit:
Beiträge: 7
Herkunft: #Neuland

Themenstarter:

beantworten | zitieren | melden

Zitat von BhaaL
Type ist auch ein Typ vom Framework, und nicht dein konkreter Typ. Vermutlich willst du eher eine generische Methode, wo tableType als Typ-Parameter reinkommt und du am Ende JsonConvert.DeserializeObject<List<TTable>>(JSONstr) machen kannst.

Okay, danke. Ist das das C#-Pentant zu C++-Templates?
Weißt du vielleicht, wo ich das passende dazu nachlesen kann?
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1768
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@1337-Cat
Du kannst dies im einfachsten Fall lösen, in dem du dir eine Helper Klasse anlegst, die dann Wrapper Methoden für die De-/Serialisierung mit generics anbieten.
Diese besteht dann nur aus den zwei Methoden und dann kannst du per Typangabe den Typen festlegen.

Generics

T-Virus
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von T-Virus am .
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.
private Nachricht | Beiträge des Benutzers
1337-Cat
myCSharp.de - Member



Dabei seit:
Beiträge: 7
Herkunft: #Neuland

Themenstarter:

beantworten | zitieren | melden

In etwa so?

class GenericJSON<T>
    {
        public List<T> parse(string JSONstr)
        {
            return JsonConvert.DeserializeObject<List<T>>(JSONstr);
        }
    }

Nun weiß ich immernoch nicht, wie ich beim Aufruf einen erst zur Laufzeit bekannten Datentyp der Methode mitteilen kann.

src.GenericJSON<???> parser = new src.GenericJSON<???>();
var results = parser.parse(JSONstr);

Weiß lediglich nur, wie ich mit Type = typeof() oder GetType() Informationen zu einem Datentyp speichern kann. Aber diese werden nicht, wo "???" steht akzeptiert.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von 1337-Cat am .
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1768
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@1337-Cat
Wieso sollten deine Datentypen erst zur Laufzeit bekannt sein bzw. warum willst du auch eine Liste von Typen übergeben?
So wirst du auch keine Daten von/in Json konvertieren.

Du willst immer nur Daten von Json in einen expliziten Typen konvertieren.
Json hat genau wie Xml und dein Code immer ein fixes Schema nach dem er aufgebaut ist.
Du kannst nicht der Serialisierung sagen, dass du hier eine Liste von X Typen hast aus der Json String geparst werden soll.
Du musst für jeden Typen einzeln eine De-/Serialisierung vornehmen.

Hier musst du dann auch den expliziten Typen, der aus dem Json generiert werden soll, angeben.
Der Json String wird dann auch auf deinen Typen gemappt.

Als Typen deiner Generic Methode musst du dann List<MyClass> hingeben, damit du auch eine Liste<MyClass> als Typen zurück bekommst.
Oder wie stellst du dir den Ablauf vor?


public class JsonHelper
{
    public static T Deserialize<T>(string json)
    {
        return JsonConvert.DeserializeObject<T>(json);
    }

    public static string Serialize(object obj)
    {
        return JsonConvert.SerializeObject(obj);
    }
}

// Beispiel Aufrufe
List<MyClass> liste = new List<MyClass>();
string json = JsonHelper.Serialize(liste);
liste = JsonHelper.Deserialize<List<MyClass>>(json);

Nachtrag:
Falls du beim deserialisieren wirklich nicht den Typen kennst, dann musst du die Deserialize Methode mit Überladung mit Type parameter nutzen.

Link

T-Virus
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von T-Virus am .
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.
private Nachricht | Beiträge des Benutzers
1337-Cat
myCSharp.de - Member



Dabei seit:
Beiträge: 7
Herkunft: #Neuland

Themenstarter:

beantworten | zitieren | melden

@T-Virus

In der Anwendung sollen Datenbanken abgeglichen werden und je nach Tabelle eine Liste von Objekten derdazugehörigen Klasse erstellt werden. Aber welcher Typ von Objekten das ist, wird erst zur Laufzeit bestimmt, abhängig davon, welche Tabellen abgeglichen werden.

Habs in etwa so gelöst, was aber auch nicht gerade schön ist.

switch (comboBox_select_table.SelectedIndex)
                {
                    case 0:
                        tableSelect = "artikel";
                        src.GenericJSON<Artikel> parser = new src.GenericJSON<Artikel>();
                        var test = parser.parse(JSONstr);
                        break;
                    case 1: tableSelect = "stueckliste";
                        src.GenericJSON<Stueckliste> p2 = new src.GenericJSON<Stueckliste>();
                        var test2 = p2.parse(JSONstr);
                        break;
                    case 2: tableSelect = "kunde";
                        src.GenericJSON<Kunde> p3 = new src.GenericJSON<Kunde>();
                        var test3 = p3.parse(JSONstr);
                        break;
                }
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1768
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@1337-Cat
Du hättest auch die static Variante nehmen können, dann musst du nur den Typen beim Deserialisieren an die Methode mitgeben.
Oder du rufst direkt nach dem Instanzieren die Parse Methode auf.


var text = new src.GenericJSON<Artikel>().parse(JSONstr);

Ich sehe hier auch Magic Numbers in deinem Code.
Nutze am besten ein Enum für deine ComboBox Werte, damit du eine einheitliche Basis hast.
Wenn einmal case 0 Artikel ist und dann einmal Kunde, welcher Wert stimmt dann?
Durch ein Enum hast du Sicherheit was der Wert bedeutet.

Nachtrag:
In deinem aktuellen Code werden die Daten zwar deserialisiert, aber dann passiert nichts mit den var test1-3.
Werden diese bei dir nur auf Gültigkeit geprüft oder passiert hier noch was?
Für Gültigkeit wäre eher ein Schema zuständig.

T-Virus
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von T-Virus am .
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.
private Nachricht | Beiträge des Benutzers
1337-Cat
myCSharp.de - Member



Dabei seit:
Beiträge: 7
Herkunft: #Neuland

Themenstarter:

beantworten | zitieren | melden

Zitat von T-Virus
Du hättest auch die static Variante nehmen können, dann musst du nur den Typen beim Deserialisieren an die Methode mitgeben.

Das war auch mein erster Plan. Aber wie soll ich das Übergeben des Datentyps dznamisch gestalten?


Zitat von T-Virus
In deinem aktuellen Code werden die Daten zwar deserialisiert, aber dann passiert nichts mit den var test1-3.
Werden diese bei dir nur auf Gültigkeit geprüft oder passiert hier noch was?
Für Gültigkeit wäre eher ein Schema zuständig.
Habe diese bis jetzt nur auf Korrektheit geprüft, und da stimmt alles so weit.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15526
Herkunft: BW

beantworten | zitieren | melden

Bei der Serialisierung des Json kannst Du das TypeNameHandling angeben.
Dann wird der konkrete Typ durch Json.NET anhand von Metadaten im Json mit angeben.

Und dann kannst Du mit simplen OOP Basics wie Interfaces arbeiten.
Alternativ musst Du bei der Deserialisierung manuell den Typ bekannt machen (durch eigene Werte oder durch Schnittstelleninformationen).

Json ist nun mal kein Typsicherer Datenaustauschkanal; fokussiert also diesen Anwendungsfall gar nicht.
Wenn Du sowas willst, dann musst Du das Protokoll wechseln (zB auf GRPC) oder Du musst Deine Kommunikationsarchitektur anpassen.
private Nachricht | Beiträge des Benutzers
1337-Cat
myCSharp.de - Member



Dabei seit:
Beiträge: 7
Herkunft: #Neuland

Themenstarter:

beantworten | zitieren | melden

Hab es irgendwie gelöst bekommen. Undzwar schreibe ich die Ergebnisse der Liste in eine DataTable. Nicht elegant, aber es funktioniert
private Nachricht | Beiträge des Benutzers