代码之家  ›  专栏  ›  技术社区  ›  Rey

使用jsonconvert.deserializeobject或jobject.parse将类反序列化为C中的字典

  •  0
  • Rey  · 技术社区  · 7 年前

    我正在asp.net core 2.2中做一个小的api项目,它获取国家、货币、语言等数据(静态数据)。

    假设我有一个json格式,如下所示:

    {
      "data": {
        "countries": [
          {
            "translatedName": "Ascension Island",
            "translations": [
              {
                "languageCode": "bg-BG",
                "translatedName": "Остров Възнесение"
              },
              {
                "languageCode": "cs-CZ",
                "translatedName": "Ascension"
              }
            ]
       }
    }
    

    我只想在 data 标记对象并将其反序列化为此类:

    class Country
    {
          public string TranslatedName { get; set; }
    
          public Dictionary<string, string> Translations { get; set; 
    } 
    

    所以我们的想法是字典的键应该是languagecode,值应该是translatedname。

    这个 数据 对象将出现在我得到的任何类型的响应中,而对于另一部分,它可能会更改。可能是 data -> countries data -> languages data -> currencies 等。

    所以解析的方法如下所示;

    public T Parse<T>(string fieldName, string json)
    {
    
    }
    

    fieldname将确定后面的第二个子名称 数据 关键,所以结构总是 data -> fieldName . 我可以更换不用的( 数据键 )从json中分离出来 string.Replace(...) 但我在想有没有更好的办法!

    第二个问题是如何反序列化字典的翻译?

    我试着用这种方法:

    public T Parse<T>(string fieldName, string json)
    {
        return JObject.Parse(json)[fieldName].ToObject<T>();
    }
    

    所以如果我用这种方法:

    var countries = Parse<List<Country>>("countries", ....); //it fails due to the fact it does not know how to convert translations to dictionary
    

    我非常感谢您的帮助:

    0 回复  |  直到 7 年前
        1
  •  0
  •   Alen.Toma    7 年前

    在这里,我为您创建了这个函数,经过测试,它可以处理您的json字符串。

    var json = "{ data: { countries: [{ translatedName: 'Ascension Island', translations: [{ languageCode: 'bg-BG', translatedName: 'Остров Възнесение'}, { languageCode: 'cs-CZ',translatedName: 'Ascension' }]}]} }";
    List<Country> countries = Parse<List<Country>>(json, "data.countries");
    public static T Parse<T>(string json, string key)
    {
        var rss = JObject.Parse(json);
        JToken jtoken = null;
        foreach (var k in key.Split('.'))
        {
            if (jtoken != null)
                jtoken = jtoken[k];
            else jtoken = rss[k];
    
        }
    
        return jtoken.ToObject<T>();
    }
    
        2
  •  -1
  •   Rey    7 年前

    最后我可以解决这个问题:

    对于@camilo提出的第一个问题,我创建了一个包装器。
    第二次我创建了一个定制的jsonconverter,它为我做了如下的工作。

    internal class TranslationsToDictionaryObjectConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(List<CountryInfoModel>).IsAssignableFrom(objectType) 
                || typeof(List<CurrencyInfoModel>).IsAssignableFrom(objectType);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JToken token = JToken.Load(reader);
            Dictionary<string, string> dict = new Dictionary<string, string>();
            try
            {
                foreach (var item in token)
                {
                    dict.Add(item["languageCode"].ToString(), item["translatedName"].ToString());
                }
            }
            catch
            {
                // ignored
            }
    
            return dict;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
        }
    }
    

    在那之后,模型看起来像:

    [Serializable]
    public class CountryInfoModel 
    {
        public int BwinId { get; set; }
    
        public string TranslatedName { get; set; }
    
        public string TwoLetterCode { get; set; }
    
        public bool LoginAllowed { get; set; }
    
        public bool RegistrationAllowed { get; set; }
    
    
        [JsonConverter(typeof(TranslationsToDictionaryObjectConverter))]
        public Dictionary<string, string> Translations { get; set; }
    }