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>
このバージョンは null 値を明示的に処理し、コントラクト リゾルバーを使用してプロパティを反復処理し、無視されるプロパティや 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()
を手動で呼び出すことが最も安全で信頼性の高いアプローチであることに注意してください。
以上がカスタム JsonConverters で `[JsonConvert()]` アノテーションを使用すると StackOverflowException が発生する場合があるのはなぜですか?また、それを防ぐにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。