2017-08-15 20 views
2

我有一些帶有本地化文本的.NET類;即文本在英語,西班牙語對應的文本,等我們有一個Locale類,看起來是這樣的:Json.NET - ContractResolver用非原始鍵序列化字典

class Locale 
{ 
    int Id; 
    string Abbreviation; // e.g. "en" 
    string Name;   // e.g. "English" 

    static Locale FromAbbreviation(string abbreviation); 
} 

本地化的文本存儲在IDictionary的屬性,像

class Document 
{ 
    IDictionary<Locale, string> Content; 
} 

當序列化到JSON,我想這對由地區縮寫被鍵入,所以序列化Document對象會是這個樣子:

{ 
    "content": { 
     "en": "English content", 
     "es": "Spanish content" 
    } 
} 

我需要一個ContractResolver是騙子將一個IDictionary<Locale, string>對象轉換爲Dictionary<string, string>對象,在序列化過程中使用Locale.Abbreviation屬性作爲鍵,並在反序列化中調用Locale.FromAbbreviation()將該鍵轉換回Locale對象。

我已經看過JSON.NET文檔和各種Stackoverflow的問題,似乎並沒有一個簡單的方法來做到這一點(至少我找不到它)。我確實發現了什麼看起來像straightforward way to do the same thing using a TypeConverter attribute,但我寧願不從我的域類中依賴Json.NET。有沒有合理的方法來使用ContractResolver來做到這一點?

回答

2

這裏您並不需要ContractResolver。您可以使用自定義JsonConverter來處理從Dictionary<Locale, string>到所需JSON的轉換,而無需在模型類中使用屬​​性。只要轉換器的CanConvert方法被正確編碼以識別轉換器處理的字典類型,那麼您可以將轉換器添加到串行器設置中,Json.Net將找到並適當地使用它。

這裏是轉換器可能是什麼樣子:

class LocaleDictionaryConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(IDictionary<Locale, string>).IsAssignableFrom(objectType); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject obj = JObject.Load(reader); 
     Dictionary<Locale, string> dict = new Dictionary<Locale, string>(); 
     foreach (var prop in obj.Properties()) 
     { 
      dict.Add(Locale.FromAbbreviation(prop.Name), (string)prop.Value); 
     } 
     return dict; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     IDictionary<Locale, string> dict = (IDictionary<Locale, string>)value; 
     JObject obj = new JObject(); 
     foreach (var kvp in dict) 
     { 
      obj.Add(kvp.Key.Abbreviation, kvp.Value); 
     } 
     obj.WriteTo(writer); 
    } 
} 

這裏是你將如何使用它序列:

var settings = new JsonSerializerSettings(); 
settings.Converters.Add(new LocaleDictionaryConverter()); 
settings.Formatting = Formatting.Indented; 

string json = JsonConvert.SerializeObject(document, settings); 

和反序列化:

// same settings as above 
var document = JsonConvert.DeserializeObject<Document>(json, settings); 

這裏演示:https://dotnetfiddle.net/f1rXl2

+0

這看起來很完美;我會給它一個旋轉。感謝您及時的回覆! –

+0

沒問題;很高興我能幫上忙。 –

+0

我需要做的唯一更改是使用ReadJson()中的existingValue參數,因爲這些類型的字典引用傾向於在我們的代碼中只讀(請參閱https://stackoverflow.com/a/27904050/2144):IDictionary < Locale,string> dict =(IDictionary )existingValue ??新詞典<語言環境,字符串>(); –

相關問題