JSON.NET StackOverflowException 和 [JsonConvert]
属性
将 [JsonConvert]
属性应用于自定义 JsonConverter
可能会在序列化期间导致 StackOverflowException
,特别是对于复杂对象。这通常是由于 JSON.NET 内部序列化过程中的无限递归造成的。虽然直接将 JsonConvert.SerializeObject()
与自定义转换器一起使用是推荐的解决方案,但本节探讨了需要该属性时的替代方法。
1。完善WriteJson
方法
问题的核心通常在于自定义转换器的 WriteJson
方法。 对边缘情况处理不充分可能会触发无限循环。 以下改进的 WriteJson
方法解决了几种常见场景:
<code class="language-csharp">public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (ReferenceEquals(value, null)) { writer.WriteNull(); return; } var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType()); writer.WriteStartObject(); foreach (var property in contract.Properties) { if (property.Ignored) continue; if (!ShouldSerialize(property, value)) continue; var propertyName = property.PropertyName; var propertyValue = property.ValueProvider.GetValue(value); writer.WritePropertyName(propertyName); if (property.Converter != null && property.Converter.CanWrite) { property.Converter.WriteJson(writer, propertyValue, serializer); } else { serializer.Serialize(writer, propertyValue); } } writer.WriteEndObject(); } private static bool ShouldSerialize(JsonProperty property, object instance) { return property.ShouldSerialize == null || property.ShouldSerialize(instance); }</code>
此版本显式处理空值,并使用合约解析器迭代属性,跳过被忽略的属性以及 ShouldSerialize
返回 false 的属性。 它还可以正确地将序列化委托给属性的转换器(如果存在并且可以写入),否则直接使用序列化器。
2。具有堆栈大小限制的递归调用
或者,您可以在 WriteJson
方法中添加堆栈深度检查,以防止失控递归:
<code class="language-csharp">public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { const int MaxStackSize = 65536; // Adjust as needed if (writer.CurrentDepth > MaxStackSize) { throw new JsonSerializationException("Stack overflow detected during serialization."); } // Your custom serialization logic here... }</code>
如果递归深度超过预定义的限制,此方法会引发描述性异常,从而防止 StackOverflowException
。 根据您的对象复杂性调整 MaxStackSize
。
结论
虽然 [JsonConvert]
属性提供了便利,但将其与自定义转换器一起使用需要仔细考虑。 通过增强 WriteJson
方法来处理边缘情况和/或合并堆栈大小检查,您可以有效降低序列化期间 StackOverflowException
的风险。 请记住,手动调用 JsonConvert.SerializeObject()
仍然是最安全、最可靠的方法。
以上是为什么将'[JsonConvert()]”注释与自定义 JsonConverters 一起使用有时会导致 StackOverflowException,如何防止它?的详细内容。更多信息请关注PHP中文网其他相关文章!