Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Z tego artykułu dowiesz się, jak serializować właściwości klas pochodnych za pomocą System.Text.Json przestrzeni nazw.
Serializowanie właściwości klas pochodnych
Począwszy od wersji .NET 7, System.Text.Json obsługuje serializację i deserializację hierarchii typów polimorficznych za pomocą adnotacji atrybutów.
| Atrybut | opis |
|---|---|
| JsonDerivedTypeAttribute | Po umieszczeniu przy deklaracji typu wskazuje, że określony podtyp powinien zostać objęty serializacją polimorficzną. Udostępnia również możliwość określenia dyskryminatora typu. |
| JsonPolymorphicAttribute | Umieszczony przy deklaracji typu oznacza, że typ powinien być serializowany polimorficznie. Udostępnia również różne opcje konfigurowania serializacji polimorficznej i deserializacji dla tego typu. |
Załóżmy na przykład, że masz klasę WeatherForecastBase i klasę pochodną 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
Załóżmy, że argumentem Serialize<TValue> typu metody w czasie kompilacji jest WeatherForecastBase:
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecastBase>(weatherForecastBase, options);
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(WeatherForecastBase, options)
W tym scenariuszu właściwość City jest serializowana, ponieważ obiekt weatherForecastBase jest w rzeczywistości obiektem WeatherForecastWithCity. Ta konfiguracja umożliwia serializację polimorficzną dla WeatherForecastBase, w szczególności gdy typ w czasie wykonywania to WeatherForecastWithCity:
{
"City": "Milwaukee",
"Date": "2022-09-26T00:00:00-05:00",
"TemperatureCelsius": 15,
"Summary": "Cool"
}
Podczas gdy przesyłanie ładunku jako WeatherForecastBase jest obsługiwane, nie zmaterializuje się jako typ WeatherForecastWithCity środowiska uruchomieniowego. Zamiast tego zmaterializuje się jako typ środowiska uruchomieniowego 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
W poniższej sekcji opisano sposób dodawania metadanych w celu włączenia zaokrąglania typu pochodnego.
Dyskryminatory typów polimorficznych
Aby włączyć deserializację polimorficzną, należy określić dyskryminację typu dla klasy pochodnej:
[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
Dzięki dodanym metadanym, a konkretnie dyskryminatorowi typu, serializator może serializować i deserializować ładunek danych jako typ WeatherForecastWithCity na podstawie jego typu bazowego WeatherForecastBase. Serializacja generuje dane JSON wraz z metadanymi dyskryminatora typu:
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"
' }
Za pomocą deskryminatora typu serializator może deserializować ładunek danych polimorficznie jako 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
Uwaga
Domyślnie $type dyskryminator musi zostać umieszczony na początku obiektu JSON, pogrupowany razem z innymi właściwościami metadanych, takimi jak $id i $ref. Jeśli odczytujesz dane z zewnętrznego interfejsu API, który umieszcza deskryminator $type w środku obiektu JSON, ustaw JsonSerializerOptions.AllowOutOfOrderMetadataProperties na true:
JsonSerializerOptions options = new() { AllowOutOfOrderMetadataProperties = true };
JsonSerializer.Deserialize<Base>("""{"Name":"Name","$type":"derived"}""", options);
Należy zachować ostrożność przy włączaniu tej flagi, ponieważ może to prowadzić do nadmiernego buforowania (i błędów z powodu braku pamięci) podczas strumieniowej deserializacji bardzo dużych obiektów JSON.
Łącz i dopasowuj formaty dyskryminatorów typów
Identyfikatory rozróżniające typy są prawidłowe zarówno w postaci string, jak i int, więc poniższy zapis jest prawidłowy:
[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...
' }
Chociaż interfejs API obsługuje łączenie różnych konfiguracji dyskryminatorów typów, nie jest to zalecane. Ogólnie zaleca się stosowanie albo wyłącznie dyskryminatorów typu string, albo wyłącznie dyskryminatorów typu int, albo żadnych dyskryminatorów. Poniższy przykład pokazuje, jak łączyć różne konfiguracje dyskryminatora typu.
[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
W poprzednim przykładzie typ BasePoint nie ma deskryminatora typu, podczas gdy typ ThreeDimensionalPoint ma deskryminator typu int, a typ FourDimensionalPoint ma deskryminator typu string.
Ważne
Aby serializacja polimorficzna działała, typ serializowanej wartości powinien być polimorficznym typem bazowym. Obejmuje to użycie typu bazowego jako parametru typu generycznego podczas serializacji wartości na poziomie głównym, jako zadeklarowanego typu serializowanych właściwości lub jako typu elementu kolekcji w serializowanych kolekcjach.
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
Dostosuj nazwę dyskryminatora typu
Domyślna nazwa właściwości dla typu dyskryminującego to $type. Aby dostosować nazwę właściwości, użyj elementu JsonPolymorphicAttribute , jak pokazano w poniższym przykładzie:
[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
W poprzednim kodzie atrybut JsonPolymorphic konfiguruje TypeDiscriminatorPropertyName na wartość "$discriminator". Po skonfigurowaniu nazwy dyskryminatora typu poniższy przykład pokazuje typ ThreeDimensionalPoint serializowany do formatu JSON:
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 }
Wskazówka
Unikaj używania JsonPolymorphicAttribute.TypeDiscriminatorPropertyName, który powoduje konflikt z właściwością w hierarchii typów.
Obsługa nieznanych typów pochodnych
Aby obsłużyć nieznane typy pochodne, należy wyrazić zgodę na taką obsługę przy użyciu adnotacji w typie podstawowym. Rozważmy następującą hierarchię typów:
[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
Ponieważ konfiguracja nie wyraża jawnej deklaracji wsparcia dla FourDimensionalPoint, próba serializacji wystąpień FourDimensionalPoint jako BasePoint spowoduje wyjątek środowiska uruchomieniowego:
JsonSerializer.Serialize<BasePoint>(new FourDimensionalPoint()); // throws NotSupportedException
JsonSerializer.Serialize(Of BasePoint)(New FourDimensionalPoint()) ' throws NotSupportedException
Domyślne zachowanie można zmienić przy użyciu wyliczenia JsonUnknownDerivedTypeHandling , które można określić w następujący sposób:
[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
Zamiast powracać do typu podstawowego, możesz użyć ustawienia FallBackToNearestAncestor, aby powracać do kontraktu najbliższego zadeklarowanego typu pochodnego:
[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
W przypadku konfiguracji podobnej do powyższego przykładu ThreeDimensionalPoint typ będzie serializowany jako BasePoint:
// Serializes using the contract for BasePoint
JsonSerializer.Serialize<IPoint>(new ThreeDimensionalPoint());
' Serializes using the contract for BasePoint
JsonSerializer.Serialize(Of IPoint)(New ThreeDimensionalPoint())
Jednak odwołanie się do najbliższego przodka dopuszcza możliwość niejednoznaczności typu „diament”. Rozważmy następującą hierarchię typów jako przykład:
[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
W takim przypadku typ BasePointWithTimeSeries może zostać zserializowany jako BasePoint albo IPointWithTimeSeries, ponieważ są one oboma bezpośrednimi typami bazowymi. Ta niejednoznaczność spowoduje zgłoszenie wyjątku NotSupportedException podczas próby serializacji instancji BasePointWithTimeSeries jako IPoint.
// throws NotSupportedException
JsonSerializer.Serialize<IPoint>(new BasePointWithTimeSeries());
' throws NotSupportedException
JsonSerializer.Serialize(Of IPoint)(New BasePointWithTimeSeries())
Wnioskowanie polimorfizmu z zamkniętej hierarchii
Począwszy od .NET 11, System.Text.Json można wywnioskować typy pochodne z zamkniętej hierarchii języka C# 15. Włącz wnioskowanie dla jednej hierarchii przez JsonPolymorphicAttribute.InferClosedTypePolymorphism:
[JsonPolymorphic(InferClosedTypePolymorphism = true)]
public closed class Shape { }
public sealed class Circle : Shape { }
public sealed class Square : Shape { }
Serializator rejestruje każdy typ pochodny i używa jego prostej nazwy jako dyskryminatora w postaci ciągu znaków. Na przykład ładunek danych Circle zawiera "$type":"Circle".
Aby włączyć wnioskowanie dla każdej zamkniętej hierarchii obsługiwanej przez wystąpienie opcji, ustaw wartość JsonSerializerOptions.InferClosedTypePolymorphism:
var options = new JsonSerializerOptions
{
InferClosedTypePolymorphism = true
};
Aby włączyć generowanie kodu źródłowego, ustaw JsonSourceGenerationOptionsAttribute.InferClosedTypePolymorphism:
[JsonSourceGenerationOptions(InferClosedTypePolymorphism = true)]
[JsonSerializable(typeof(Shape))]
internal partial class AppJsonContext : JsonSerializerContext;
Ustaw inferencję dla atrybutu generowania kodu źródłowego, gdy używasz wygenerowanego kontekstu. Samo włączenie właściwości JsonSerializerOptions w środowisku wykonawczym nie umożliwia dodania metadanych typu pochodnego, których generator źródłowy nie wygenerował.
Atrybut na poziomie typu ma pierwszeństwo przed ustawieniem globalnym. Ustaw InferClosedTypePolymorphism = false w elemencie JsonPolymorphicAttribute, aby wykluczyć jedną hierarchię z ustawienia globalnego.
Jawne JsonDerivedTypeAttribute rejestracje zastępują wnioskowanie dla tej hierarchii. Nie rozszerzają one wywnioskowanej listy. Zastosowanie InferClosedTypePolymorphism = true do typu, który nie jest closed, zgłasza wyjątek InvalidOperationException w przypadku serializacji opartej na refleksji i powoduje błąd podczas generowania kodu źródłowego. Wywnioskowane typy z zduplikowanymi prostymi nazwami generują kolizje dyskryminacyjne, a każdy typ wnioskowany musi być co najmniej tak dostępny, jak zamknięta baza.
Konfigurowanie otwartych typów pochodnych ogólnych
Począwszy od platformy .NET 11 element JsonDerivedTypeAttribute akceptuje otwarty pochodny typ generyczny, gdy serializator może ustalić unikatowy typ zamknięty na podstawie zserializowanego typu podstawowego:
[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
Dla Base<int> serializator rejestruje Derived<int>. To samo rozstrzyganie obsługuje interfejsy generyczne, parametry typów w zmienionej kolejności, zagnieżdżone argumenty generyczne, tablice oraz typy pochodne, które ustalają niektóre argumenty typu bazowego na konkretne typy.
Każdy parametr typu pochodnego musi być wnioskowany z zamkniętego typu podstawowego, podstawianie musi być jednoznaczne, a wynikowy typ musi spełniać jego ograniczenia ogólne. Serializacja oparta na refleksji zgłasza InvalidOperationException w przypadku nieobsługiwanej specjalizacji. Generowanie źródła zgłasza SYSLIB1229, a wygenerowana hierarchia nadal kończy się niepowodzeniem, gdy serializator ją konfiguruje. Pomijanie ostrzeżenia nie powoduje prawidłowej rejestracji.
Konfigurowanie polimorfizmu przy użyciu modelu kontraktu
W przypadkach użycia, w których stosowanie atrybutów jest niepraktyczne lub niemożliwe (na przykład w przypadku dużych modeli domenowych, hierarchii obejmujących wiele zestawów lub hierarchii w zależnościach innych firm), do konfigurowania polimorfizmu użyj modelu kontraktu. Model kontraktów to zestaw interfejsów API, których można używać do konfigurowania polimorfizmu w hierarchii typów przez utworzenie niestandardowej podklasy DefaultJsonTypeInfoResolver, która dynamicznie udostępnia konfigurację polimorficzną dla każdego typu, jak pokazano w poniższym przykładzie:
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
Dodatkowe szczegóły serializacji polimorficznej
- Serializacja polimorficzna obsługuje typy pochodne, które zostały jawnie uwzględnione za pomocą elementu JsonDerivedTypeAttribute. Typy niezadeklarowane spowodują wyjątek środowiska uruchomieniowego. Zachowanie można zmienić, konfigurując JsonPolymorphicAttribute.UnknownDerivedTypeHandling właściwość .
- Konfiguracja polimorficzna określona w typach pochodnych nie jest dziedziczona przez konfigurację polimorficzną w typach bazowych. Typ podstawowy musi być skonfigurowany niezależnie.
- Hierarchie polimorficzne są obsługiwane zarówno dla
interfacetypów, jak iclass. - Polimorfizm z użyciem dyskryminatorów typów jest obsługiwany wyłącznie dla hierarchii typów, które używają domyślnych konwerterów dla obiektów, kolekcji i typów słownikowych.
- Polimorfizm jest obsługiwany w generowaniu kodu źródłowego opartym na metadanych, ale nie w generowaniu kodu źródłowego w trybie fast-path.