2016-03-25 12 views
3

ein Wörterbuch zu json von Newtonsoft.json und brüllen Code serialisiert:Newtonsoft.Json, Populate Wörterbuch fehlgeschlagen

var serializeSettings = new JsonSerializerSettings 
     { 
      TypeNameHandling = TypeNameHandling.All, 
      TypeNameAssemblyFormat = FormatterAssemblyStyle.Full, 
      Formatting = Formatting.Indented 
     }; 
     var serializedObject = JsonConvert.SerializeObject(dic, serializeSettings); 

diesem Code erzeugen ein Json wie folgt aus:

{ 
    "$type": "System.Collections.Generic.Dictionary`2[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 
    "9648af76-7986-4b34-8b2c-97b2345769ef": "Test" 
} 

Ich versuche zu deserialisieren json von diesem Code-Wörterbuch:

var newDic = new Dictionay<Guid,string>(); 
var deserializeSettings = new JsonSerializerSettings 
{ 
    TypeNameHandling = TypeNameHandling.All, 
    TypeNameAssemblyFormat = FormatterAssemblyStyle.Full, 
    Formatting = Formatting.Indented 
} 
JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings); 

Aber diese Ausnahme auftritt:

Die Zeichenfolge '$ type' konnte nicht in den Dictionary-Schlüsseltyp 'System.Guid' konvertiert werden. Erstellen Sie einen TypeConverter, um von der Zeichenfolge in das Schlüsseltypobjekt zu konvertieren. Pfad '$ Typ', Zeile 2, Position 10.

bei Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary (IDictionary Wörterbuch, JsonReader Leser, JsonDictionaryContract Vertrag, JsonProperty containerProperty, String id)

bei Newtonsoft.Json .Serialization.JsonSerializerInternalReader.Populate (JsonReader reader, Zielobjekt)

bei Newtonsoft.Json.JsonSerializer.PopulateInternal (JsonReader reader, Zielobjekt)

bei Newtonsoft.Json.JsonSerializer.Populate (JsonReader reader, Zielobjekt)

bei Newtonsoft.Json.JsonConvert.PopulateObject (String Wert, Objekt Ziel, JsonSerializerSettings Einstellungen)

Ich schreibe GuidConverter wie diese und verwenden. aber nicht funktionieren

public class GuidConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType.IsAssignableFrom(typeof(Guid)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     try 
     { 
      return serializer.Deserialize<Guid>(reader); 
     } 
     catch 
     { 
      return Guid.Empty; 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 
} 

EDIT:

Ich fand mein Problem. Code ändern deserialisieren json zu Wörterbuch < string, string> und jetzt Erster Eintrag in generierten Wörterbuch ist:

Kay: "$type" 
Value : "System.Collections.Generic.Dictionary`2[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 

Warum ??

+1

Brauchen Sie die spezielle Einstellung und die Guid? Vielleicht versuchen Sie etwas einfacheres wie 'JsonConvert.SerializeObject (dic);' und sehen, ob das gibt Ihnen, was Sie brauchen. – senschen

+0

@ssenschen Ich verwende eine generische Klasse, um mehrere Typen in meinem Projekt zu serialisieren und zu deserialisieren. Andere Typen in meinem Projekt müssen diese Einstellungen verwenden. Bitte lesen Sie die letzte Änderung meiner Frage – Fred

+0

Verwenden Sie Zeichenfolge anstelle von Guid @Fred –

Antwort

4

Das Problem ist, dass Sie beim Serialisieren Ihres Wörterbuchs TypeNameHandling = TypeNameHandling.All angegeben haben. Dies führt zu einem Metadaten "$type" Eigenschaft als das erste Objekt in dem Wörterbuch emittiert werden:

{ 
    "$type": "System.Collections.Generic.Dictionary`2[[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 
    "9648af76-7986-4b34-8b2c-97b2345769ef": "Test" 
} 

Wenn DeserializeObject Deserialisieren Verwendung dieser Token normalerweise durch Json.NET verbraucht wird, wenn das entsprechende C# Objekt aufgebaut ist. Aber Sie verwenden PopulateObject für ein im Voraus zugewiesenes Wörterbuch. Daher wird die Metadateneigenschaft während der Erstellung nicht verbraucht und stattdessen versucht Json.NET, sie zum Wörterbuch hinzuzufügen und schlägt fehl.

Die Lösung ist MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead in deserializeSettings zu setzen.Dadurch kann dich die "$type" Eigenschaft verbraucht oder ignoriert werden (je nach Bedarf) bedingungslos:

var deserializeSettings = new JsonSerializerSettings 
{ 
    TypeNameHandling = TypeNameHandling.All, 
    TypeNameAssemblyFormat = FormatterAssemblyStyle.Full, 
    Formatting = Formatting.Indented, 
    MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead 
}; 
JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings); 

Bitte zur Kenntnis, dass von den release notes, eineine leicht Kosten im Speicherverbrauch und Geschwindigkeit sind von dieser Einstellung.

Alternativ, wenn Sie bedingungslos keine Metadaten Typinformationen in Ihrem JSON müssen, können Sie mit TypeNameHandling = TypeNameHandling.Auto serialisiert und nur Typinformationen für polymorphe Typen emittieren, die Ihre Dictionary<Guid, string> nicht.

+1

Vielen Dank. Ihre Lösung funktioniert gut. – Fred