无法将JSON序列化至含字典属性类的问题求助(涉及YAML转JSON)
解决JSON序列化至含字典属性类的问题
嘿,我来帮你搞定这个JSON序列化到带字典属性类的麻烦事儿!首先得明确问题核心:你现在的YAML结构里,should_be_dic_element是一组单键对象的数组(用-开头标记数组元素),所以转成JSON后自然是对象数组,而你的类里对应的属性应该是字典类型,这就导致了“无法序列化为字典”的报错。
问题根源分析
先看你的输入和输出:
YAML内容:
some_element: '1' should_be_dic_element: - a: '1' - b: '2'JSON输出:
{ "some_element": "1", "should_be_dic_element": [ { "a": "1" }, { "b": "2" } ] }
这个JSON里的should_be_dic_element是数组,不是字典,所以没法匹配类里的字典属性。下面给你两种解决方案,按需选择:
方案1:修改YAML输入格式(最直接)
如果能调整YAML的写法,把数组改成直接的键值对(去掉-),就能直接生成字典格式的JSON:
some_element: '1' should_be_dic_element: a: '1' b: '2'
转出来的JSON会变成:
{ "some_element": "1", "should_be_dic_element": { "a": "1", "b": "2" } }
这样你的类只要定义字典属性就能正常序列化了,类定义示例:
public class SomeClass { [JsonProperty(PropertyName = "some_element")] public string SomeElement { get; set; } [JsonProperty(PropertyName = "should_be_dic_element")] public Dictionary<string, string> ShouldBeDicElement { get; set; } }
方案2:无法修改YAML时,在转换过程中处理数组转字典
如果不能改YAML输入,那就在YAML转JSON的流程里,把数组里的单键对象合并成字典,这里给你两种实现方式:
方式A:用YamlDotNet自定义转换器
创建一个自定义类型转换器,在反序列化YAML时直接把数组转成字典:
public class SingleKeyArrayToDictionaryConverter : IYamlTypeConverter { public bool Accepts(Type type) { // 只处理Dictionary类型 return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>); } public object ReadYaml(IParser parser, Type type) { var keyType = type.GetGenericArguments()[0]; var valueType = type.GetGenericArguments()[1]; var dictionary = (IDictionary)Activator.CreateInstance(type); // 先消耗映射开始节点 parser.Consume<MappingStart>(); while (parser.Current != null && parser.Current is not MappingEnd) { // 如果遇到序列(数组)节点,处理里面的单键对象 if (parser.Current is SequenceStart) { parser.Consume<SequenceStart>(); while (parser.Current is not SequenceEnd) { parser.Consume<MappingStart>(); // 取单键对象的键和值 var keyScalar = parser.Consume<Scalar>(); var valueScalar = parser.Consume<Scalar>(); parser.Consume<MappingEnd>(); // 转换类型后加入字典 var key = Convert.ChangeType(keyScalar.Value, keyType); var value = Convert.ChangeType(valueScalar.Value, valueType); dictionary.Add(key, value); } parser.Consume<SequenceEnd>(); break; } // 兼容正常的键值对格式 else { var keyScalar = parser.Consume<Scalar>(); var valueScalar = parser.Consume<Scalar>(); var key = Convert.ChangeType(keyScalar.Value, keyType); var value = Convert.ChangeType(valueScalar.Value, valueType); dictionary.Add(key, value); } } parser.Consume<MappingEnd>(); return dictionary; } public void WriteYaml(IEmitter emitter, object value, Type type) { // 如果需要序列化字典到YAML,可以在这里实现,暂时省略 throw new NotImplementedException(); } }
然后在反序列化YAML时注册这个转换器:
var deserializer = new DeserializerBuilder() .WithTypeConverter(new SingleKeyArrayToDictionaryConverter()) .Build(); var someClass = deserializer.Deserialize<SomeClass>(yourYamlContent); // 之后再转JSON也没问题了 var jsonStr = JsonConvert.SerializeObject(someClass);
方式B:先转JObject再手动处理
先把YAML转成JObject,然后手动遍历数组转成字典,再序列化为目标类:
// 1. YAML转成JObject var yamlDeserializer = new Deserializer(); var yamlObj = yamlDeserializer.Deserialize<object>(yourYamlContent); var jsonStr = JsonConvert.SerializeObject(yamlObj); var jObj = JObject.Parse(jsonStr); // 2. 处理should_be_dic_element数组转字典 var arrayNode = jObj["should_be_dic_element"] as JArray; var targetDic = new Dictionary<string, string>(); foreach (var item in arrayNode) { // 取每个单键对象的第一个属性 var property = item.First as JProperty; targetDic.Add(property.Name, property.Value.ToString()); } // 替换原来的数组节点为字典 jObj["should_be_dic_element"] = JObject.FromObject(targetDic); // 3. 转成目标类 var someClass = jObj.ToObject<SomeClass>();
总结
如果能修改YAML,优先用方案1,最省心;如果不能改输入,方案2的两种方式都能解决问题,自定义转换器更适合复用,手动处理JObject则更灵活,按需选择就好。
内容的提问来源于stack exchange,提问作者guyl
相关产品推荐
相关产品推荐

