问题描述
我正在编写一个 JsonConverter
来执行一些我需要在读/写时完成的转换任务.特别是,我采用了现有的序列化行为,并在写入/读取时添加了一些附加属性.
I'm writing a JsonConverter
to perform some conversion tasks I need accomplished on read/write. In particular, I'm taking the existing serialization behavior and tacking on some additional properties on write / reading those additional properties on read.
在 JsonConverter
中,我想利用传递的 JsonSerializer
实例来执行大部分转换功能.但是,当我这样做时,我最终会进入一个递归循环,其中序列化程序调用我的转换器,然后调用序列化程序,然后调用转换器等等.
Inside the JsonConverter
, I'd like to make use of the passed JsonSerializer
instance to perform the majority of the conversion functionality. However, when I do this, I end up in a recursive loop where the serializer calls into my converter which calls into the serializer which calls into the converter and etc.
我见过人们使用 JsonConvert.SerializeObject
,从序列化器实例 except this
传入所有转换器.但是,这对我不起作用,因为它绕过了我在序列化程序上完成的所有其他自定义,例如自定义合同解析器和 DateTime
处理.
I've seen people do things such as use JsonConvert.SerializeObject
, passing in all the converters from the serializer instance except this
. However, that won't work for me because it bypasses all of the other customization I've done on my serializer, such as custom contract resolver and DateTime
handling.
有没有办法:
- 使用传递给我的序列化程序实例,但以某种方式排除我的转换器,或者
- 克隆传递给我的序列化程序(无需手动构建一个新序列化程序并逐个属性地复制它)并删除我的转换器?
推荐答案
这是一个很常见的问题.使用JsonConvert.SerializeObject"不是一个坏主意.但是,在某些情况下(通常是集合)可以使用的一个技巧是在写入时强制转换为接口,并在读取时反序列化为简单的派生.
This is a very common problem. Using "JsonConvert.SerializeObject" isn't a bad idea. However, one trick that can be used in some circumstances (typically collections) is to cast to the interface when writing and deserialize to a simple derivative when reading.
下面是一个简单的转换器,它处理可能被序列化为一组 KVP 而不是看起来像一个对象的字典(在这里显示我的年龄 :))
Below is a simple converter that deals with dictionaries that might have been serialized as a set of KVPs rather than looking like an object (showing my age here :) )
注意WriteJson"转换为 IDictionary
K,V> 和ReadJson"使用DummyDictionary".您最终得到了正确的结果,但使用了传递的序列化程序而不会导致递归.
Note "WriteJson" casts to IDictionary< K,V> and "ReadJson" uses "DummyDictionary". You end up with the right thing but uses the passed serializer without causing recursion.
/// <summary>
/// Converts a <see cref="KeyValuePair{TKey,TValue}"/> to and from JSON.
/// </summary>
public class DictionaryAsKVPConverter<TKey, TValue> : JsonConverter
{
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
if (!objectType.IsValueType && objectType.IsGenericType)
return (objectType.GetGenericTypeDefinition() == typeof(Dictionary<,>));
return false;
}
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var dictionary = value as IDictionary<TKey, TValue>;
serializer.Serialize(writer, dictionary);
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
Dictionary<TKey, TValue> dictionary;
if (reader.TokenType == JsonToken.StartArray)
{
dictionary = new Dictionary<TKey, TValue>();
reader.Read();
while (reader.TokenType == JsonToken.StartObject)
{
var kvp = serializer.Deserialize<KeyValuePair<TKey, TValue>>(reader);
dictionary[kvp.Key] = kvp.Value;
reader.Read();
}
}
else if (reader.TokenType == JsonToken.StartObject)
// Use DummyDictionary to fool JsonSerializer into not using this converter recursively
dictionary = serializer.Deserialize<DummyDictionary>(reader);
else
dictionary = new Dictionary<TKey, TValue>();
return dictionary;
}
/// <summary>
/// Dummy to fool JsonSerializer into not using this converter recursively
/// </summary>
private class DummyDictionary : Dictionary<TKey, TValue> { }
}
这篇关于在 JsonConverter 中递归调用 JsonSerializer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!