Json.NET - 使用非原始键序列化字典的ContractResolver

时间:2017-08-15 14:39:34

标签: c# json serialization json.net

我有一些带有本地化文本的.NET类;即英文文本,西班牙语相应文本等。我​​们有一个Locale类,如下所示:

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时,我希望这可以通过locale缩写来键入,因此序列化的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有合理的方法吗?

1 个答案:

答案 0 :(得分: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);
        IDictionary<Locale, string> dict = (IDictionary<Locale, string>)existingValue ?? 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