Language

System.Text.Json で派生クラスのプロパティをシリアル化する方法

この記事では、System.Text.Json 名前空間を使用して派生クラスのプロパティをシリアル化する方法について説明します。

派生クラスのプロパティのシリアル化

.NET 7 以降の System.Text.Json では、ポリモーフィック型の階層のシリアル化と属性注釈による逆シリアル化がサポートされています。

属性 説明
JsonDerivedTypeAttribute 型宣言に配置された場合、指定したサブタイプをポリモーフィックなシリアル化にオプトインする必要があることを示します。 また、型判別子を指定する機能も公開されます。
JsonPolymorphicAttribute 型宣言に配置された場合、型をポリモーフィックにシリアル化する必要があることを示します。 また、その型のポリモーフィックなシリアル化と逆シリアル化を構成するためのさまざまなオプションも公開されています。

たとえば、WeatherForecastBase クラスと派生クラス WeatherForecastWithCity があるとします。

[JsonDerivedType(typeof(WeatherForecastWithCity))]
public class WeatherForecastBase
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}
<JsonDerivedType(GetType(WeatherForecastWithCity))>
Public Class WeatherForecastBase
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As String
End Class
public class WeatherForecastWithCity : WeatherForecastBase
{
    public string? City { get; set; }
}
Public Class WeatherForecastWithCity
    Inherits WeatherForecastBase
    Public Property City As String
End Class

また、コンパイル時の Serialize<TValue> メソッドの型引数が WeatherForecastBase であるとします。

options = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecastBase>(weatherForecastBase, options);
options = New JsonSerializerOptions With {
    .WriteIndented = True
}
jsonString = JsonSerializer.Serialize(WeatherForecastBase, options)

このシナリオでは、City オブジェクトが実際には weatherForecastBase オブジェクトであるため、WeatherForecastWithCity プロパティはシリアル化されません。 この構成では、特にランタイムの種類が WeatherForecastBase である場合に、WeatherForecastWithCity のポリモーフィックなシリアル化が有効になります。

{
  "City": "Milwaukee",
  "Date": "2022-09-26T00:00:00-05:00",
  "TemperatureCelsius": 15,
  "Summary": "Cool"
}

WeatherForecastBaseとしてのペイロードのラウンドトリップはサポートされていますが、ランタイムの種類のWeatherForecastWithCityとして具体化されません。 代わりに、ランタイム型の WeatherForecastBaseとして具体化されます。

WeatherForecastBase value = JsonSerializer.Deserialize<WeatherForecastBase>("""
    {
      "City": "Milwaukee",
      "Date": "2022-09-26T00:00:00-05:00",
      "TemperatureCelsius": 15,
      "Summary": "Cool"
    }
    """);

Console.WriteLine(value is WeatherForecastWithCity); // False
Dim value As WeatherForecastBase = JsonSerializer.Deserialize(@"
    {
      "City": "Milwaukee",
      "Date": "2022-09-26T00:00:00-05:00",
      "TemperatureCelsius": 15,
      "Summary": "Cool"
    }")

Console.WriteLine(value is WeatherForecastWithCity) // False

次のセクションでは、派生型のラウンドトリップを有効にするためにメタデータを追加する方法について説明します。

ポリモーフィック型の判別子

ポリモーフィックな逆シリアル化を有効にするには、派生クラスの型判別子を指定する必要があります。

[JsonDerivedType(typeof(WeatherForecastBase), typeDiscriminator: "base")]
[JsonDerivedType(typeof(WeatherForecastWithCity), typeDiscriminator: "withCity")]
public class WeatherForecastBase
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

public class WeatherForecastWithCity : WeatherForecastBase
{
    public string? City { get; set; }
}
<JsonDerivedType(GetType(WeatherForecastBase), "base")>
<JsonDerivedType(GetType(WeatherForecastWithCity), "withCity")>
Public Class WeatherForecastBase
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As String
End Class

Public Class WeatherForecastWithCity
    Inherits WeatherForecastBase
    Public Property City As String
End Class

追加されたメタデータ (具体的には、型判別子) を使用すると、シリアライザーでは、基本型 WeatherForecastWithCity からペイロードを WeatherForecastBase 型としてシリアル化および逆シリアル化できます。 シリアル化を行うと、JSON データは型識別子のメタデータが付加されて出力されます。

WeatherForecastBase weather = new WeatherForecastWithCity
{
    City = "Milwaukee",
    Date = new DateTimeOffset(2022, 9, 26, 0, 0, 0, TimeSpan.FromHours(-5)),
    TemperatureCelsius = 15,
    Summary = "Cool"
}
var json = JsonSerializer.Serialize<WeatherForecastBase>(weather, options);
Console.WriteLine(json);
// Sample output:
//   {
//     "$type" : "withCity",
//     "City": "Milwaukee",
//     "Date": "2022-09-26T00:00:00-05:00",
//     "TemperatureCelsius": 15,
//     "Summary": "Cool"
//   }
Dim weather As WeatherForecastBase = New WeatherForecastWithCity With
{
    .City = "Milwaukee",
    .[Date] = New DateTimeOffset(2022, 9, 26, 0, 0, 0, TimeSpan.FromHours(-5)),
    .TemperatureCelsius = 15,
    .Summary = "Cool"
}
Dim json As String = JsonSerializer.Serialize(weather, options)
Console.WriteLine(json)
' Sample output:
'   {
'     "$type" : "withCity",
'     "City": "Milwaukee",
'     "Date": "2022-09-26T00:00:00-05:00",
'     "TemperatureCelsius": 15,
'     "Summary": "Cool"
'   }

型判別子を使用すると、シリアライザーでは、次のように、ペイロードを WeatherForecastWithCity としてポリモーフィックに逆シリアル化できます。

WeatherForecastBase value = JsonSerializer.Deserialize<WeatherForecastBase>(json);
Console.WriteLine(value is WeatherForecastWithCity); // True
Dim value As WeatherForecastBase = JsonSerializer.Deserialize(json)
Console.WriteLine(value is WeatherForecastWithCity) // True

注

既定では、$type 識別子は $id や $ref などの他のメタデータ プロパティと共に、JSON オブジェクトの先頭に配置する必要があります。 外部 API から読み取る JSON データで、$type 識別子が JSON オブジェクトの途中に配置されているような場合は、JsonSerializerOptions.AllowOutOfOrderMetadataProperties を true に設定します。

JsonSerializerOptions options = new() { AllowOutOfOrderMetadataProperties = true };
JsonSerializer.Deserialize<Base>("""{"Name":"Name","$type":"derived"}""", options);

このフラグを有効にする場合は注意してください。非常に大きな JSON オブジェクトをストリーミングにより逆シリアル化すると、過剰なバッファリング (およびメモリ不足エラー) が発生する可能性があるためです。

型識別子の形式を組み合わせる

型判別子の識別子は、string または int のいずれかの形式で有効であるため、以下は有効となります。

[JsonDerivedType(typeof(WeatherForecastWithCity), 0)]
[JsonDerivedType(typeof(WeatherForecastWithTimeSeries), 1)]
[JsonDerivedType(typeof(WeatherForecastWithLocalNews), 2)]
public class WeatherForecastBase { }

var json = JsonSerializer.Serialize<WeatherForecastBase>(new WeatherForecastWithTimeSeries());
Console.WriteLine(json);
// Sample output:
//   {
//    "$type" : 1,
//    Omitted for brevity...
//   }
<JsonDerivedType(GetType(WeatherForecastWithCity), 0)>
<JsonDerivedType(GetType(WeatherForecastWithTimeSeries), 1)>
<JsonDerivedType(GetType(WeatherForecastWithLocalNews), 2)>
Public Class WeatherForecastBase
End Class

Dim json As String = JsonSerializer.Serialize(Of WeatherForecastBase)(New WeatherForecastWithTimeSeries())
Console.WriteLine(json)
' Sample output:
'  {
'    "$type" : 1,
'    Omitted for brevity...
'  }

API では、型判別子の構成の混在と一致がサポートされていますが、推奨はされません。 一般的に推奨されるのは、すべての string 型判別子を使用する、すべての int 型判別子を使用する、まったく判別子を使用しない、のいずれかです。 次の例は、型判別子の構成を混在させ、一致させる方法を示しています。

[JsonDerivedType(typeof(ThreeDimensionalPoint), typeDiscriminator: 3)]
[JsonDerivedType(typeof(FourDimensionalPoint), typeDiscriminator: "4d")]
public class BasePoint
{
    public int X { get; set; }
    public int Y { get; set; }
}

public class ThreeDimensionalPoint : BasePoint
{
    public int Z { get; set; }
}

public sealed class FourDimensionalPoint : ThreeDimensionalPoint
{
    public int W { get; set; }
}
<JsonDerivedType(GetType(ThreeDimensionalPoint), 3)>
<JsonDerivedType(GetType(FourDimensionalPoint), "4d")>
Public Class BasePoint
    Public Property X As Integer
    Public Property Y As Integer
End Class

Public Class ThreeDimensionalPoint
    Inherits BasePoint
    Public Property Z As Integer
End Class

Public NotInheritable Class FourDimensionalPoint
    Inherits ThreeDimensionalPoint
    Public Property W As Integer
End Class

前の例では、BasePoint 型には型判別子がありませんが、ThreeDimensionalPoint 型には int 型判別子があり、FourDimensionalPoint には string 型判別子があります。

重要

ポリモーフィックなシリアル化を機能させるには、シリアル化される値の型をポリモーフィック基本型の型とする必要があります。 これには、ルートレベルの値をシリアル化するときのジェネリック型パラメーターとして、シリアル化されたプロパティの宣言された型として、またはシリアル化されたコレクションのコレクション要素として、基本型を使用することが含まれます。

using System.Text.Json;
using System.Text.Json.Serialization;

PerformRoundTrip<BasePoint>();
PerformRoundTrip<ThreeDimensionalPoint>();
PerformRoundTrip<FourDimensionalPoint>();

static void PerformRoundTrip<T>() where T : BasePoint, new()
{
    var json = JsonSerializer.Serialize<BasePoint>(new T());
    Console.WriteLine(json);

    BasePoint? result = JsonSerializer.Deserialize<BasePoint>(json);
    Console.WriteLine($"result is {typeof(T)}; // {result is T}");
    Console.WriteLine();
}
// Sample output:
//   { "X": 541, "Y": 503 }
//   result is BasePoint; // True
//
//   { "$type": 3, "Z": 399, "X": 835, "Y": 78 }
//   result is ThreeDimensionalPoint; // True
//
//   { "$type": "4d", "W": 993, "Z": 427, "X": 508, "Y": 741 }
//   result is FourDimensionalPoint; // True
Imports System.Text.Json
Imports System.Text.Json.Serialization

Module Program
    Sub Main()
        PerformRoundTrip(Of BasePoint)()
        PerformRoundTrip(Of ThreeDimensionalPoint)()
        PerformRoundTrip(Of FourDimensionalPoint)()
    End Sub

    Private Sub PerformRoundTrip(Of T As {BasePoint, New})()
        Dim json = JsonSerializer.Serialize(Of BasePoint)(New T())
        Console.WriteLine(json)

        Dim result As BasePoint = JsonSerializer.Deserialize(Of BasePoint)(json)
        Console.WriteLine($"result is {GetType(T)}; // {TypeOf result Is T}")
        Console.WriteLine()
    End Sub
End Module
' Sample output:
'   { "X": 649, "Y": 754 }
'   result is BasePoint; // True
'
'   { "$type": 3, "Z": 247, "X": 814, "Y": 56 }
'   result is ThreeDimensionalPoint; // True
'
'   { "$type": "4d", "W": 427, "Z": 193, "X": 112, "Y": 935 }
'   result is FourDimensionalPoint; // True

型識別子名をカスタマイズする

型識別子の既定のプロパティ名は $type です。 プロパティ名をカスタマイズするには、JsonPolymorphicAttribute を次の例のように使用します。

[JsonPolymorphic(TypeDiscriminatorPropertyName = "$discriminator")]
[JsonDerivedType(typeof(ThreeDimensionalPoint), typeDiscriminator: "3d")]
public class BasePoint
{
    public int X { get; set; }
    public int Y { get; set; }
}

public sealed class ThreeDimensionalPoint : BasePoint
{
    public int Z { get; set; }
}
<JsonPolymorphic(TypeDiscriminatorPropertyName:="$discriminator")>
<JsonDerivedType(GetType(ThreeDimensionalPoint), "3d")>
Public Class BasePoint
    Public Property X As Integer
    Public Property Y As Integer
End Class

Public Class ThreeDimensionalPoint
    Inherits BasePoint
    Public Property Z As Integer
End Class

上記のコードでは、JsonPolymorphic 属性によって TypeDiscriminatorPropertyName が "$discriminator" 値に構成されます。 次の例では、型識別子の名前が構成されている場合に、JSON としてシリアル化された ThreeDimensionalPoint 型を示しています。

BasePoint point = new ThreeDimensionalPoint { X = 1, Y = 2, Z = 3 };
var json = JsonSerializer.Serialize<BasePoint>(point);
Console.WriteLine(json);
// Sample output:
//  { "$discriminator": "3d", "X": 1, "Y": 2, "Z": 3 }
Dim point As BasePoint = New ThreeDimensionalPoint With { .X = 1, .Y = 2, .Z = 3 }
Dim json As String = JsonSerializer.Serialize(Of BasePoint)(point)
Console.WriteLine(json)
' Sample output:
'  { "$discriminator": "3d", "X": 1, "Y": 2, "Z": 3 }

ヒント

型階層内のプロパティと競合する JsonPolymorphicAttribute.TypeDiscriminatorPropertyName の使用は避けてください。

不明な派生型を処理する

不明な派生型を処理するには、基本型の注釈を使用して、このようなサポートを選択する必要があります。 次の型階層を考えてみましょう。

[JsonDerivedType(typeof(ThreeDimensionalPoint))]
public class BasePoint
{
    public int X { get; set; }
    public int Y { get; set; }
}

public class ThreeDimensionalPoint : BasePoint
{
    public int Z { get; set; }
}

public class FourDimensionalPoint : ThreeDimensionalPoint
{
    public int W { get; set; }
}
<JsonDerivedType(GetType(ThreeDimensionalPoint))>
Public Class BasePoint
    Public Property X As Integer
    Public Property Y As Integer
End Class

Public Class ThreeDimensionalPoint
    Inherits BasePoint
    Public Property Z As Integer
End Class

Public NotInheritable Class FourDimensionalPoint
    Inherits ThreeDimensionalPoint
    Public Property W As Integer
End Class

構成では FourDimensionalPointのサポートが明示的にオプトインされないため、 FourDimensionalPoint のインスタンスを BasePoint としてシリアル化しようとすると、ランタイム例外が発生します。

JsonSerializer.Serialize<BasePoint>(new FourDimensionalPoint()); // throws NotSupportedException
JsonSerializer.Serialize(Of BasePoint)(New FourDimensionalPoint()) ' throws NotSupportedException

JsonUnknownDerivedTypeHandling 列挙型を使用すれば、既定の動作を変更できます。これは、次のように指定できます。

[JsonPolymorphic(
    UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)]
[JsonDerivedType(typeof(ThreeDimensionalPoint))]
public class BasePoint
{
    public int X { get; set; }
    public int Y { get; set; }
}

public class ThreeDimensionalPoint : BasePoint
{
    public int Z { get; set; }
}

public class FourDimensionalPoint : ThreeDimensionalPoint
{
    public int W { get; set; }
}
<JsonPolymorphic(
    UnknownDerivedTypeHandling:=JsonUnknownDerivedTypeHandling.FallBackToBaseType)>
<JsonDerivedType(GetType(ThreeDimensionalPoint))>
Public Class BasePoint
    Public Property X As Integer
    Public Property Y As Integer
End Class

Public Class ThreeDimensionalPoint
    Inherits BasePoint
    Public Property Z As Integer
End Class

Public NotInheritable Class FourDimensionalPoint
    Inherits ThreeDimensionalPoint
    Public Property W As Integer
End Class

基本型にフォールバックするのでなく、FallBackToNearestAncestor 設定を使用して最も近い宣言された派生型のコントラクトにフォールバックできます。

[JsonPolymorphic(
    UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)]
[JsonDerivedType(typeof(BasePoint))]
public interface IPoint { }

public class BasePoint : IPoint { }

public class ThreeDimensionalPoint : BasePoint { }
<JsonPolymorphic(
    UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)>
<JsonDerivedType(GetType(BasePoint)>
Public Interface IPoint
End Interface

Public Class BasePoint
    Inherits IPoint
End Class

Public Class ThreeDimensionalPoint
    Inherits BasePoint
End Class

前の例のような構成を使用すると、ThreeDimensionalPoint 型は次のように BasePoint としてシリアル化されます。

// Serializes using the contract for BasePoint
JsonSerializer.Serialize<IPoint>(new ThreeDimensionalPoint());
' Serializes using the contract for BasePoint
JsonSerializer.Serialize(Of IPoint)(New ThreeDimensionalPoint())

ただし、最も近い祖先にフォールバックすると、"ダイヤモンド" のあいまいさの可能性が認められます。 例として次の型階層を考えてみます。

[JsonPolymorphic(
    UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)]
[JsonDerivedType(typeof(BasePoint))]
[JsonDerivedType(typeof(IPointWithTimeSeries))]
public interface IPoint { }

public interface IPointWithTimeSeries : IPoint { }

public class BasePoint : IPoint { }

public class BasePointWithTimeSeries : BasePoint, IPointWithTimeSeries { }
<JsonPolymorphic(
    UnknownDerivedTypeHandling:=JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)>
<JsonDerivedType(GetType(BasePoint))>
<JsonDerivedType(GetType(IPointWithTimeSeries))>
Public Interface IPoint
End Interface

Public Interface IPointWithTimeSeries
    Inherits IPoint
End Interface

Public Class BasePoint
    Implements IPoint
End Class

Public Class BasePointWithTimeSeries
    Inherits BasePoint
    Implements IPointWithTimeSeries
End Class

この場合、BasePointWithTimeSeries 型は BasePoint または IPointWithTimeSeries としてシリアル化することが可能です。それらは、両方とも直接の先祖だからです。 この曖昧さにより、BasePointWithTimeSeries のインスタンスを IPoint としてシリアル化しようとすると、NotSupportedException が送出されます。

// throws NotSupportedException
JsonSerializer.Serialize<IPoint>(new BasePointWithTimeSeries());
' throws NotSupportedException
JsonSerializer.Serialize(Of IPoint)(New BasePointWithTimeSeries())

閉じた階層からポリモーフィズムを推論する

.NET 11 以降では、System.Text.Jsonは C# 15 の閉じた階層から派生型を推論できます。 JsonPolymorphicAttribute.InferClosedTypePolymorphismを使用して、1 つの階層で推論を有効にします。

[JsonPolymorphic(InferClosedTypePolymorphism = true)]
public closed class Shape { }
public sealed class Circle : Shape { }
public sealed class Square : Shape { }

シリアライザーは、各派生型を登録し、その単純型名を文字列識別子として使用します。 たとえば、 Circle ペイロードには "$type":"Circle"が含まれています。

オプション インスタンスが処理するすべての閉じた階層に対して推論を有効にするには、 JsonSerializerOptions.InferClosedTypePolymorphism設定します。

var options = new JsonSerializerOptions
{
    InferClosedTypePolymorphism = true
};

ソース生成の場合は、 JsonSourceGenerationOptionsAttribute.InferClosedTypePolymorphism設定します。

[JsonSourceGenerationOptions(InferClosedTypePolymorphism = true)]
[JsonSerializable(typeof(Shape))]
internal partial class AppJsonContext : JsonSerializerContext;

生成されたコンテキストを使用するときに、ソース生成属性に推論を設定します。 ランタイム JsonSerializerOptions プロパティのみを有効にすると、ソース ジェネレーターが出力しなかった派生型のメタデータを追加することはできません。

型レベルの属性は、グローバル設定よりも優先されます。 グローバル設定から 1 つの階層を選択するには、JsonPolymorphicAttributeにInferClosedTypePolymorphism = falseを設定します。

明示的な JsonDerivedTypeAttribute 登録は、その階層の推論を置き換えます。 推論されたリストは拡張されません。 closedではない型にInferClosedTypePolymorphism = trueを適用すると、リフレクション ベースのシリアル化でInvalidOperationExceptionがスローされ、ソース生成エラーが発生します。 重複する単純名を持つ推論された型は識別子の競合を発生させ、推論されるすべての型は、少なくとも閉じたベースと同じくらいアクセス可能である必要があります。

オープン ジェネリック派生型を構成する

.NET 11 以降では、シリアライザーがシリアル化された基本型から一意の閉じた型を解決できる場合、JsonDerivedTypeAttributeはオープン ジェネリック派生型を受け入れます。

[JsonDerivedType(typeof(Derived<>), "derived")]
public class Base<T>;
public class Derived<T> : Base<T>;
<JsonDerivedType(GetType(Derived(Of )), "derived")>
Public Class Base(Of T)
End Class
Public Class Derived(Of T)
    Inherits Base(Of T)
End Class

Base<int>の場合、シリアライザーはDerived<int>を登録します。 同じ解像度では、ジェネリック インターフェイス、並べ替え型パラメーター、入れ子になったジェネリック引数、配列、および一部の基本型引数を具象型に修正する派生型がサポートされます。

すべての派生型パラメーターは、閉じた基本型から推論できる必要があり、置換は明確である必要があり、結果の型はそのジェネリック制約を満たす必要があります。 リフレクション ベースのシリアル化では、未サポートの特殊化に対して InvalidOperationException が送出されます。 ソース生成では SYSLIB1229 が報告され、生成された階層は、シリアライザーがそれを構成するときにも引き続き失敗します。 警告を抑制しても、登録は有効になりません。

コントラクト モデルを使用してポリモーフィズムを構成する

属性注釈が実用的でない、または適切でないというユース ケース (大規模なドメイン モデル、アセンブリ間階層、サード パーティの依存関係の階層など) の場合、ポリモーフィズムを構成するには、コントラクト モデルを使用します。 コントラクト モデルは API のセットであり、これを使用することで、次の例に示すように、型ごとに動的にポリモーフィック構成を提供するカスタム DefaultJsonTypeInfoResolver サブクラスを作成して、型階層内にポリモーフィズムを構成することができます。

public class PolymorphicTypeResolver : DefaultJsonTypeInfoResolver
{
    public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
    {
        JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);

        Type basePointType = typeof(BasePoint);
        if (jsonTypeInfo.Type == basePointType)
        {
            jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
            {
                TypeDiscriminatorPropertyName = "$point-type",
                IgnoreUnrecognizedTypeDiscriminators = true,
                UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization,
                DerivedTypes =
                {
                    new JsonDerivedType(typeof(ThreeDimensionalPoint), "3d"),
                    new JsonDerivedType(typeof(FourDimensionalPoint), "4d")
                }
            };
        }

        return jsonTypeInfo;
    }
}
Public Class PolymorphicTypeResolver
    Inherits DefaultJsonTypeInfoResolver

    Public Overrides Function GetTypeInfo(
        ByVal type As Type,
        ByVal options As JsonSerializerOptions) As JsonTypeInfo

        Dim jsonTypeInfo As JsonTypeInfo = MyBase.GetTypeInfo(type, options)
        Dim basePointType As Type = GetType(BasePoint)

        If jsonTypeInfo.Type = basePointType Then
            jsonTypeInfo.PolymorphismOptions = New JsonPolymorphismOptions With {
                .TypeDiscriminatorPropertyName = "$point-type",
                .IgnoreUnrecognizedTypeDiscriminators = True,
                .UnknownDerivedTypeHandling =
                    JsonUnknownDerivedTypeHandling.FailSerialization
            }
            jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(
                New JsonDerivedType(GetType(ThreeDimensionalPoint), "3d"))
            jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(
                New JsonDerivedType(GetType(FourDimensionalPoint), "4d"))
        End If

        Return jsonTypeInfo
    End Function
End Class

その他のポリモーフィックなシリアル化の詳細

  • ポリモーフィックなシリアル化では、JsonDerivedTypeAttribute を介して明示的にオプトインされた派生型がサポートされます。 宣言されていない型の場合、ランタイム例外が発生します。 この動作は、JsonPolymorphicAttribute.UnknownDerivedTypeHandling プロパティを構成することにより変更できます。
  • 派生型で指定されたポリモーフィック構成は、基本型のポリモーフィック構成では継承されません。 基本型は個別に構成する必要があります。
  • ポリモーフィック階層は、interface および class の両方の型でサポートされています。
  • 型判別子を使用するポリモーフィズムは、オブジェクト、コレクション、ディクショナリ型用の既定のコンバーターを使用する型階層でのみサポートされます。
  • ポリモーフィズムは、メタデータ ベースのソース生成ではサポートされていますが、高速パス ソースの生成ではサポートされていません。

関連項目