Json.NET - CustomCreationConverter 中单个属性的默认反序列化行为
Posted
技术标签:
【中文标题】Json.NET - CustomCreationConverter 中单个属性的默认反序列化行为【英文标题】:Json.NET - Default deserialization behavior for a single property in CustomCreationConverter 【发布时间】:2014-02-27 13:31:42 【问题描述】:在以下场景中,当CrazyItemConverter
遇到我要反序列化到的类型中存在的 JSON 属性时,如何让它照常进行?
我有一些如下所示的 JSON:
"Item":
"Name":"Apple",
"Id":null,
"Size":5,
"Quality":2
JSON 被反序列化为一个看起来很像这样的类:
[JsonConverter(typeof(CrazyItemConverter))]
public class Item
[JsonConverter(typeof(CrazyStringConverter))]
public string Name get; set;
public Guid? Id get; set;
[JsonIgnore]
public Dictionary<string, object> CustomFields
get
if (_customFields == null)
_customFields = new Dictionary<string, object>();
return _customFields;
...
CrazyItemConverter
填充已知属性的值并将未知属性放入 CustomFields。其中的ReadJson
如下所示:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
var outputObject = Create(objectType);
var objProps = objectType.GetProperties().Select(p => p.Name).ToArray();
while (reader.Read())
if (reader.TokenType == JsonToken.PropertyName)
string propertyName = reader.Value.ToString();
if (reader.Read())
if (objProps.Contains(propertyName))
// No idea :(
// serializer.Populate(reader, outputObject);
else
outputObject.AddProperty(propertyName, reader.Value);
return outputObject;
在反序列化过程中,当CrazyItemConverter
遇到已知属性时,我希望它能够正常运行。意思是,尊重[JsonConverter(typeof(CrazyStringConverter))]
为Name
。
我是使用下面的代码来设置已知属性,但是,它会在 nullables 上引发异常并且不尊重我的其他 JsonConverters。
PropertyInfo pi = outputObject.GetType().GetProperty(readerValue, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType);
pi.SetValue(outputObject, convertedValue, null);
有什么想法吗?
更新:我了解到 serializer.Populate(reader, outputObject);
是如何反序列化整个事情,但如果您希望逐个属性地使用默认功能,它似乎不起作用。
【问题讨论】:
【参考方案1】:如果我理解正确,您的 CrazyItemConverter
存在,以便您可以将 JSON 中的已知属性反序列化为强类型属性,同时仍将可能在 JSON 中的“额外”字段保留到字典中。
事实证明 Json.Net 已经内置了这个功能(从 5.0 第 5 版开始),所以你不需要一个疯狂的转换器。相反,您只需要使用[JsonExtensionData]
属性标记您的字典。 (有关更多信息,请参阅the author's blog。)
所以你的 Item 类看起来像这样:
public class Item
[JsonConverter(typeof(CrazyStringConverter))]
public string Name get; set;
public Guid? Id get; set;
[JsonExtensionData]
public Dictionary<string, object> CustomFields
get
if (_customFields == null)
_customFields = new Dictionary<string, object>();
return _customFields;
private set
_customFields = value;
private Dictionary<string, object> _customFields;
然后你可以像往常一样反序列化它。演示:
class Program
static void Main(string[] args)
string json = @"
""Item"":
""Name"":""Apple"",
""Id"":""4b7e9f9f-7a30-4f79-8e47-8b50ea26ddac"",
""Size"":5,
""Quality"":2
";
Item item = JsonConvert.DeserializeObject<Wrapper>(json).Item;
Console.WriteLine("Name: " + item.Name);
Console.WriteLine("Id: " + item.Id);
foreach (KeyValuePair<string, object> kvp in item.CustomFields)
Console.WriteLine(kvp.Key + ": " + kvp.Value);
public class Wrapper
public Item Item get; set;
class CrazyStringConverter : JsonConverter
public override bool CanConvert(Type objectType)
return objectType == typeof(string);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
JToken token = JToken.Load(reader);
// Reverse the string just for fun
return new string(token.ToString().Reverse().ToArray());
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
输出:
Name: elppA
Id: 4b7e9f9f-7a30-4f79-8e47-8b50ea26ddac
Size: 5
Quality: 2
【讨论】:
是否可以在不向模型类引入 JSON 特定属性的情况下实现类似的功能?以上是关于Json.NET - CustomCreationConverter 中单个属性的默认反序列化行为的主要内容,如果未能解决你的问题,请参考以下文章
json.net 到 System.text.json 对 .net 5 中嵌套类的期望