【发布时间】:2021-08-04 05:50:43
【问题描述】:
问题的细节可能有点长,所以我在开头简单描述一下:如何强制Json.Net使用其默认的对象序列化器(或者忽略其他的特定的自定义转换器)字),但在反序列化对象时仍将设置保留在 JsonSerializer 中?
为我糟糕的英语道歉,描述可能有点模棱两可和令人困惑。我会用我的详细场景来解释它。
在处理 HTTP 响应时,我们有时会遇到对象是其父对象的唯一子对象的场景,这使得父对象在某种程度上成为了无意义的对象包装器。在一些糟糕的设计中,可能有多个级别的此类包装器。如果我们想在不自定义的情况下正确反序列化这样的 JSON,我们必须按照结构来定义那些包装类,这绝对是没有意义和烦人的,因此我想出了创建一个通用 ObjectWrapperConverter 的想法.代码如下:
public class ObjectWrapperConverter<T> : ObjectWrapperConverterBase<T> {
public ObjectWrapperConverter(string propertyName) : this(propertyName, Array.Empty<JsonConverter>()) { }
public ObjectWrapperConverter(string propertyName, params JsonConverter[] converters) {
PropertyName = propertyName;
Converters = converters;
}
public override string PropertyName { get; }
public override JsonConverter[] Converters { get; }
}
public abstract class ObjectWrapperConverterBase<T> : JsonConverter<T> {
public abstract string PropertyName { get; }
public abstract JsonConverter[] Converters { get; }
public sealed override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer) {
writer.WriteStartObject();
writer.WritePropertyName(PropertyName);
serializer.Converters.AddRange(Converters);
writer.WriteValue(value, serializer);
serializer.Converters.RemoveRange(Converters);
writer.WriteEndObject();
}
public sealed override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer) {
var token = JToken.Load(reader);
if (token.Type != JTokenType.Object)
throw new JTokenTypeException(token, JTokenType.Object);
var obj = token as JObject;
var prop = obj!.Property(PropertyName);
if (prop is null)
throw new JTokenException(token, $"Property \"{PropertyName}\" not found");
serializer.Converters.AddRange(Converters);
var result = prop.Value.ToObject<T>(serializer);//BUG: recurse when applying JsonConverterAttribute to a class
serializer.Converters.RemoveRange(Converters);
return result;
}
}
当我将JsonConverterAttribute 放在属性和字段上时,它工作正常。但是在注解类的时候,问题就出现了:反序列化过程陷入了递归循环。
我调试到 Json.Net 框架,并意识到当为类指定自定义转换器时,Json.Net 将始终使用此转换器来处理此类的序列化,除非更高优先级的属性(如放置在属性上的 JsonConverterAttribute)被注释。因此,在我的转换器中,我发表评论的那一行最终会导致递归。
如果您了解了这个转换器的用途,很容易发现这个转换器只是一个中间件:添加或移除包装器对象,然后继续原来的序列化过程。
那么,如何才能继续“原始”序列化过程,而不是再次陷入转换器本身呢?
【问题讨论】:
-
有关某些选项,请参阅JSON.Net throws StackOverflowException when using
[JsonConvert()]。事实上,这可能是重复的,同意吗?不能 100% 确定,因为您的问题缺少完整的 minimal reproducible example。 -
@dbc 感谢您的链接!这正是我正在寻找的。我设法以一种棘手的方式解决了这个问题。如果有人遇到类似问题,我会自己回答问题。
标签: c# serialization json.net