2017-09-25 1 views
0

Ich versuche, ein Wörterbuch serialisieren/deserialisieren, das Problem ist, dass ich das Wörterbuch mit einem StringComparer.OrdinalIgnoreCase Vergleich erstellen.Deserialize JSON Dictionary mit StringComparer

Hier ist ein Code-Snippet des Problems Ich erlebe:

var dict = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 

dict["x"] = new Dictionary<string, string>(); 
dict["x"]["y"] = "something"; 

var serialized = JsonConvert.SerializeObject(dict); 

var unSerialized = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(serialized); 

Console.WriteLine((dict.Comparer == unSerialized.Comparer ? "Same" : "Different")); 

(.NET Fiddle - Try It)

Druckt die folgenden auf der Konsole:

Different

Offensichtlich ist die Der JSON-Serializer serialisiert den Comparer, den ich beim Erstellen des Wörterbuchs eingerichtet habe, nicht, aber das Problem kann ich nicht einstellen Der Comparer nach der Tat seit Dictionary<TKey, TValue>.Comparer ist schreibgeschützt.

Ich bin mir sicher, dass es mit einigen benutzerdefinierten JsonSerializerSetting zu tun hat, aber ich kann nicht herausfinden, wie man die Sammlungserstellung abfangen und ein Wörterbuch mit einem anderen Vergleich zurückgeben.

+0

OK Nehmen wir an, Sie schicken diesen JSON an eine andere Seite. Wie kann es wissen, wie Sie dieses Wörterbuch erstellt haben (Sie können sogar andere Methoden ohne jedes Wörterbuch verwenden, um dasselbe json zu erstellen) –

+0

@ L.B Diese Anwendung ist nicht webbasiert, ich verwende JSON für die Serialisierung über XML aus anderen geschäftlichen Gründen. Die Daten werden nicht von einem externen System verarbeitet. –

+0

Es ist nur ein Beispiel, um die Logik zu erklären. Empfänger des JSON hat keine Ahnung, wie Sie es erstellt haben. Es kennt nicht einmal die Sprache, mit der Sie es erstellt haben. Sie machen also falsche Annahmen –

Antwort

2

können Sie auch bevölkert ein bestehendes Objekt mit PopulateObject:

var dict = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 

dict["x"] = new Dictionary<string, string>(); 
dict["x"]["y"] = "something"; 

var json = JsonConvert.SerializeObject(dict); 


var result = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 
JsonConvert.PopulateObject(json, result); 

Console.WriteLine(result["x"]["y"]); 
Console.WriteLine(result.Comparer == dict.Comparer ? "Same" : "Diff"); 

Ausgang:

something 
Same 
+0

Danke, das funktioniert genau so wie ich es brauche. –

1

Sie die comparer angeben können im Konstruktor Ihres Wörterbuch zu verwenden, wenn Sie sowohl das Ergebnis der Deserialisierung und die comparer Sie an den Konstruktor eines neuen Wörterbuch verwenden möchten passieren:

var unSerialized = 
    new Dictionary<string, Dictionary<string, string>> 
     (JsonConvert 
      .DeserializeObject<Dictionary<string, Dictionary<string, string>>>(serialized), 
      dict.Comparer); 
+0

Danke, ich dachte nicht, es als eine Sammlung im Konstruktor des Wörterbuchs zurückzugeben. –

2

Es ist wahrscheinlich ein bisschen spät, aber es ist möglich, generiert JSON mit JsonConverter wird etwas komplexer, aber flexibler. Ich habe eine Probe für den beschriebenen Fall erstellt, ist es nicht voll
.NET Fiddle - Try It
(fühlen Sie sich frei zu verlängern, wenn Sie es benutzen würde entscheiden):

public class DictConverter<TValue> : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return true; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var obj = JToken.ReadFrom(reader);     
     if (objectType == typeof(Dictionary<string, TValue>)) 
     { 
      var comparer = obj.Value<string>("Comparer"); 
      Dictionary<string, TValue> result; 
      if (comparer == "OrdinalIgnoreCase") 
      { 
       result = new Dictionary<string, TValue>(StringComparer.OrdinalIgnoreCase); 
      } 
      else 
      { 
       result = new Dictionary<string, TValue>(); 
      } 
      obj["Comparer"].Parent.Remove(); 
      serializer.Populate(obj.CreateReader(), result); 
      return result; 
     } 
     return obj.ToObject(objectType); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var obj = JObject.FromObject(value); 
     if (value is Dictionary<string, TValue>) 
     { 
      if((value as Dictionary<string, TValue>).Comparer == StringComparer.OrdinalIgnoreCase) 
       obj.Add("Comparer", JToken.FromObject("OrdinalIgnoreCase")); 
     } 
     obj.WriteTo(writer); 

    } 
} 

und Nutzung

var dict = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 

dict["x"] = new Dictionary<string, string>(); 
dict["x"]["y"] = "something"; 

var serialized = JsonConvert.SerializeObject(dict, 
    new DictConverter<Dictionary<string,string>>()); 
var unSerialized = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>> 
    (serialized, new DictConverter<Dictionary<string, string>>());