ホームページ > バックエンド開発 > C++ > カスタム JsonConverters で `[JsonConvert()]` アノテーションを使用すると StackOverflowException が発生する場合があるのはなぜですか?また、それを防ぐにはどうすればよいですか?

カスタム JsonConverters で `[JsonConvert()]` アノテーションを使用すると StackOverflowException が発生する場合があるのはなぜですか?また、それを防ぐにはどうすればよいですか?

Patricia Arquette
リリース: 2025-01-20 15:25:15
オリジナル
704 人が閲覧しました

Why does using the `[JsonConvert()]` annotation with custom JsonConverters sometimes result in a StackOverflowException, and how can I prevent it?

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 サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート