使用 JsonConvert.DeserializeObject 或 JObject.Parse 将类反序列化为 c# 中的字典
Posted
技术标签:
【中文标题】使用 JsonConvert.DeserializeObject 或 JObject.Parse 将类反序列化为 c# 中的字典【英文标题】:Deserialize a class to a dictionary in c# using JsonConvert.DeserializeObject or JObject.Parse 【发布时间】:2019-07-15 16:47:09 【问题描述】:我正在 Asp.Net Core 2.2 中制作一个小型 API 项目,用于获取国家、货币、语言等数据(静态数据)。
假设我的 JSON 格式如下:
"data":
"countries": [
"translatedName": "Ascension Island",
"translations": [
"languageCode": "bg-BG",
"translatedName": "Остров Възнесение"
,
"languageCode": "cs-CZ",
"translatedName": "Ascension"
]
我只想获取data
标签对象中的 JSON 文本并将其反序列化为此类:
class Country
public string TranslatedName get; set;
public Dictionary<string, string> Translations get; set;
所以这个想法是字典的键是languageCode,值是translatedName。
data
对象将出现在我收到的任何类型的响应中,而对于另一部分它可能会改变。可能是data -> countries
,或者data -> languages
,或者data -> currencies
等等。
所以解析的方法如下所示;
public T Parse<T>(string fieldName, string json)
fieldName 将确定data
键之后的第二个子名称,因此结构将始终为data -> fieldName
。我可以通过说string.Replace(...)
来替换 JSON 中未使用的(数据键)部分,但我正在考虑是否有更好的方法来做到这一点!
第二个问题是如何将翻译反序列化为字典?
我尝试在方法中做这样的事情:
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
我非常感谢任何帮助:
【问题讨论】:
对于第一个问题,我通常只使用一个包装器:public class Wrapper<T> public T Data get; set;
并将其用于反序列化
"字典的键是 languageCode,值是 translateName。" 不幸的是,没有从 json 直接映射到您尝试执行的操作。 Json 对象可以表示为字典,但是此类字典的键将是 json 属性名称。根据您的 json,这样的字典将具有例如字符串 "languageCode"
作为键,字符串值为 "bg-BG"
。您需要处理“翻译”列表中的 json 对象并相应地构建您的字典...
@CamiloTerevinto 是的,我其实也是这么想的,但后来我搞砸了第二部分,不知何故完全忘记了包装纸(手掌)
保持强类型并创建一个翻译类以便使用public List<Translation> Translations get; set;
会有什么问题吗?
@CamiloTerevinto 的问题是,在第二步中我搜索翻译,如果它是一个列表,那么与字典相比它的性能不高。所以我想要一本字典的唯一原因是提高搜索性能。我可以再添加一个属性并根据列表创建该字典,但正在考虑是否有更好的方法,并且由于这是一个库,因此消费者会混淆使用哪个属性,因为其中一个属性应该被取消,因为它被缓存了之后。因此,如果消费者尝试使用 Translations 列表,则会得到一个空异常
【参考方案1】:
我在这里为你创建了这个函数,经过测试,它可以与你的 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】:终于可以解决问题了:
对于@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;
【讨论】:
你究竟为什么要这么做?我告诉过你,它适用于默认的序列化程序。你做错了什么 @CamiloTerevinto 这里是一个小提琴:dotnetfiddle.net/WQlfF7#,检查错误 因为结构错误,你有Dictionary<string, string> Translations
,而你应该有List<Dictionary<string, string>> Translations
@CamiloTerevinto 对我来说没有意义为每个翻译创建一个字典,最后翻译是一个键值对(twoLetterCode - translateName)而不是电子字典,你可以那样做好吧,但没有任何好处,尤其是在搜索方面,因为您仍然必须在列表中搜索,然后从仅包含条目的字典中获取数据以上是关于使用 JsonConvert.DeserializeObject 或 JObject.Parse 将类反序列化为 c# 中的字典的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?