Származtatott osztályok tulajdonságainak szerializálása System.Text.Json
Ebből a cikkből megtudhatja, hogyan szerializálhatja a származtatott osztályok tulajdonságait a System.Text.Json
névtérrel.
Származtatott osztályok tulajdonságainak szerializálása
A .NET 7 System.Text.Json
előtti verziók nem támogatják a polimorf típusú hierarchiák szerializálását. Ha például egy tulajdonság típusa interfész vagy absztrakt osztály, akkor a rendszer csak a felületen vagy absztrakt osztályban meghatározott tulajdonságokat szerializálja, még akkor is, ha a futtatókörnyezet típusa további tulajdonságokkal rendelkezik. A viselkedésre vonatkozó kivételeket ebben a szakaszban ismertetjük. A .NET 7 támogatásáról további információt a .NET 7 polimorf szerializációjában talál.
Tegyük fel például, hogy van egy WeatherForecast
osztálya és egy származtatott osztálya WeatherForecastDerived
:
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
Public Class WeatherForecast
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
End Class
public class WeatherForecastDerived : WeatherForecast
{
public int WindSpeed { get; set; }
}
Public Class WeatherForecastDerived
Inherits WeatherForecast
Public Property WindSpeed As Integer
End Class
Tegyük fel, hogy a metódus típusargumentuma fordításkor Serialize
a következő WeatherForecast
:
var options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecast>(weatherForecast, options);
Dim options As JsonSerializerOptions = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast1, options)
Ebben az esetben a WindSpeed
tulajdonság akkor sem szerializálódik, ha az weatherForecast
objektum objektum WeatherForecastDerived
. Csak az alaposztály tulajdonságai vannak szerializálva:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Ez a viselkedés segít megelőzni az adatok véletlen expozícióját egy származtatott futtatókörnyezet által létrehozott típusban.
Az előző példában a származtatott típus tulajdonságainak szerializálásához használja az alábbi módszerek egyikét:
Adjon meg egy túlterhelést Serialize , amely lehetővé teszi a típus futásidőben történő megadását:
options = new JsonSerializerOptions { WriteIndented = true }; jsonString = JsonSerializer.Serialize(weatherForecast, weatherForecast.GetType(), options);
options = New JsonSerializerOptions With { .WriteIndented = True } jsonString = JsonSerializer.Serialize(weatherForecast1, weatherForecast1.[GetType](), options)
Deklarálja a szerializálandó objektumot
object
.options = new JsonSerializerOptions { WriteIndented = true }; jsonString = JsonSerializer.Serialize<object>(weatherForecast, options);
options = New JsonSerializerOptions With { .WriteIndented = True } jsonString = JsonSerializer.Serialize(Of Object)(weatherForecast1, options)
Az előző példaforgatókönyvben mindkét módszer miatt a WindSpeed
tulajdonság szerepel a JSON-kimenetben:
{
"WindSpeed": 35,
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Fontos
Ezek a megközelítések csak a gyökérobjektum szerializálásához biztosítják a polimorf szerializálást, a gyökérobjektum tulajdonságaihoz nem.
Az alacsonyabb szintű objektumok polimorf szerializálását is lekérheti, ha típusként object
definiálja őket. Tegyük fel például, hogy az WeatherForecast
osztálynak van egy olyan tulajdonsága, PreviousForecast
amely típusként WeatherForecast
vagy object
:
public class WeatherForecastWithPrevious
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
public WeatherForecast? PreviousForecast { get; set; }
}
Public Class WeatherForecastWithPrevious
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
Public Property PreviousForecast As WeatherForecast
End Class
public class WeatherForecastWithPreviousAsObject
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
public object? PreviousForecast { get; set; }
}
Public Class WeatherForecastWithPreviousAsObject
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
Public Property PreviousForecast As Object
End Class
Ha a PreviousForecast
tulajdonság a következő példányt WeatherForecastDerived
tartalmazza:
- A szerializálásból
WeatherForecastWithPrevious
származó JSON-kimenet nem tartalmazza a következőtWindSpeed
: . - A szerializálásból
WeatherForecastWithPreviousAsObject
származó JSON-kimenet tartalmazza a következőtWindSpeed
: .
A szerializáláshoz WeatherForecastWithPreviousAsObject
nem szükséges meghívni Serialize<object>
, vagy GetType
mert nem a gyökérobjektum lehet származtatott típusú. A következő példakód nem hívható meg Serialize<object>
vagy GetType
:
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject, options);
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject1, options)
Az előző kód helyesen szerializálja a következőt WeatherForecastWithPreviousAsObject
:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot",
"PreviousForecast": {
"WindSpeed": 35,
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
}
A tulajdonságok definiálásának ugyanaz a megközelítése, mint az object
interfészekkel. Tegyük fel, hogy a következő felülettel és implementációval rendelkezik, és implementációs példányokat tartalmazó tulajdonságokkal szeretne szerializálni egy osztályt:
namespace SystemTextJsonSamples
{
public interface IForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
public class Forecast : IForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
public int WindSpeed { get; set; }
}
public class Forecasts
{
public IForecast? Monday { get; set; }
public object? Tuesday { get; set; }
}
}
Namespace SystemTextJsonSamples
Public Interface IForecast
Property [Date] As DateTimeOffset
Property TemperatureCelsius As Integer
Property Summary As String
End Interface
Public Class Forecast
Implements IForecast
Public Property [Date] As DateTimeOffset Implements IForecast.[Date]
Public Property TemperatureCelsius As Integer Implements IForecast.TemperatureCelsius
Public Property Summary As String Implements IForecast.Summary
Public Property WindSpeed As Integer
End Class
Public Class Forecasts
Public Property Monday As IForecast
Public Property Tuesday As Object
End Class
End Namespace
Amikor szerializál egy példányt Forecasts
, csak Tuesday
a WindSpeed
tulajdonság jelenik meg, mert Tuesday
a következőként object
van definiálva:
var forecasts = new Forecasts
{
Monday = new Forecast
{
Date = DateTime.Parse("2020-01-06"),
TemperatureCelsius = 10,
Summary = "Cool",
WindSpeed = 8
},
Tuesday = new Forecast
{
Date = DateTime.Parse("2020-01-07"),
TemperatureCelsius = 11,
Summary = "Rainy",
WindSpeed = 10
}
};
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(forecasts, options);
Dim forecasts1 As New Forecasts With {
.Monday = New Forecast With {
.[Date] = Date.Parse("2020-01-06"),
.TemperatureCelsius = 10,
.Summary = "Cool",
.WindSpeed = 8
},
.Tuesday = New Forecast With {
.[Date] = Date.Parse("2020-01-07"),
.TemperatureCelsius = 11,
.Summary = "Rainy",
.WindSpeed = 10
}
}
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(forecasts1, options)
Az alábbi példa az előző kódból származó JSON-t mutatja be:
{
"Monday": {
"Date": "2020-01-06T00:00:00-08:00",
"TemperatureCelsius": 10,
"Summary": "Cool"
},
"Tuesday": {
"Date": "2020-01-07T00:00:00-08:00",
"TemperatureCelsius": 11,
"Summary": "Rainy",
"WindSpeed": 10
}
}
Feljegyzés
Ez a cikk szerializálásról, nem deszerializálásról szól. A .NET 7 előtti verziók nem támogatják a polimorf deszerializálást, de kerülő megoldásként egyéni konvertert írhat, például a Polimorf deszerializálás támogatása című példában. Ha többet szeretne tudni arról, hogy a .NET 7 hogyan támogatja a polimorf szerializálást és a deszerializálást, olvassa el a Származtatott osztályok System.Text.Json tulajdonságainak szerializálása a .NET 7-ben című témakört.
A .NET 7-től System.Text.Json
kezdve támogatja a polimorf típusú hierarchia szerializálását és deszerializálását attribútumjegyzetekkel.
Attribútum | Leírás |
---|---|
JsonDerivedTypeAttribute | Típusdeklarációra helyezve azt jelzi, hogy a megadott altípust polimorf szerializálásra kell alkalmazni. Emellett lehetővé teszi a típuskriminatív megadását is. |
JsonPolymorphicAttribute | Típusdeklarációra helyezve azt jelzi, hogy a típust polimorfikusan kell szerializálni. Emellett különböző lehetőségeket is kínál a polimorf szerializálás és a deszerializálás konfigurálásához az adott típushoz. |
Tegyük fel például, hogy van egy WeatherForecastBase
osztálya és egy származtatott osztálya 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
Tegyük fel, hogy a metódus típusargumentuma fordításkor Serialize<TValue>
a következő WeatherForecastBase
:
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecastBase>(weatherForecastBase, options);
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(WeatherForecastBase, options)
Ebben a forgatókönyvben a City
tulajdonság szerializálva van, mert az weatherForecastBase
objektum valójában egy WeatherForecastWithCity
objektum. Ez a konfiguráció lehetővé teszi a polimorf szerializálástWeatherForecastBase
, különösen akkor, ha a futtatókörnyezet típusa:WeatherForecastWithCity
{
"City": "Milwaukee",
"Date": "2022-09-26T00:00:00-05:00",
"TemperatureCelsius": 15,
"Summary": "Cool"
}
Bár a hasznos adat WeatherForecastBase
ciklikus bemásolása a támogatott módon történik, nem fog futásidejű WeatherForecastWithCity
típusként megvalósulni. Ehelyett a következő futásidejű WeatherForecastBase
típusként fog megvalósulni:
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
Az alábbi szakasz azt ismerteti, hogyan adhat hozzá metaadatokat a származtatott típus ciklikus lehatolásának engedélyezéséhez.
Polimorf típusú diszkriminatívok
A polimorf deszerializálás engedélyezéséhez meg kell adnia egy típuskriminálót a származtatott osztályhoz:
[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
A hozzáadott metaadatokkal, pontosabban a típuskriminálóval a szerializáló szerializálhatja és deszerializálhatja a hasznos adatokat az WeatherForecastWithCity
alaptípus WeatherForecastBase
típusaként. A szerializálás JSON-t bocsát ki a típuskriminatív metaadatokkal együtt:
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"
' }
A típus diszkriminatív használatával a szerializáló a hasznos adatokat polimorfikusan deszerializálhatja a következő módon 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
Feljegyzés
Alapértelmezés szerint a megkülönböztetést $type
a JSON-objektum elején kell elhelyezni, más metaadat-tulajdonságokkal( például $id
és $ref
. Ha adatokat olvas egy külső API-ból, amely a megkülönböztetést $type
a JSON-objektum közepén helyezi el, állítsa a JsonSerializerOptions.AllowOutOfOrderMetadataProperties következőre true
:
JsonSerializerOptions options = new() { AllowOutOfOrderMetadataProperties = true };
JsonSerializer.Deserialize<Base>("""{"Name":"Name","$type":"derived"}""", options);
Legyen óvatos, amikor engedélyezi ezt a jelzőt, mert ez túlpuffereltséget (és memóriakimaradást) okozhat a nagyon nagy JSON-objektumok streamelt deszerializálása során.
Típuskriminatív formátumok keverése és egyeztetése
A típuskriminatív azonosítók vagy string
int
űrlapok érvényesek, ezért a következők érvényesek:
[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...
' }
Bár az API támogatja a keverő és a típuskriminatív konfigurációk egyeztetését, nem ajánlott. Az általános ajánlás az, hogy vagy minden string
típus-diszkriminatívt, minden int
típus-diszkriminatívt, vagy egyáltalán ne használjon diszkriminatívokat. Az alábbi példa a típuskriminatív konfigurációk keverését és egyezését mutatja be:
[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
Az előző példában a BasePoint
típus nem rendelkezik típuskriminálóval, míg a ThreeDimensionalPoint
típus int
típuskriminatív, a FourDimensionalPoint
string
típus diszkriminatív.
Fontos
A polimorf szerializálás működéséhez a szerializált érték típusának a polimorf alaptípusnak kell lennie. Ez magában foglalja az alaptípus általános típusparaméterként való használatát a gyökérszintű értékek szerializálásakor, a szerializált tulajdonságok deklarált típusaként vagy a szerializált gyűjtemények gyűjteményelemeként.
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
A típus diszkriminatív nevének testreszabása
A típuskriminatív alapértelmezett tulajdonságneve a következő $type
: . A tulajdonság nevének testreszabásához használja az JsonPolymorphicAttribute alábbi példában látható módon:
[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
Az előző kódban az JsonPolymorphic
attribútum konfigurálja az TypeDiscriminatorPropertyName
"$discriminator"
értéket. A típuskriminatív név konfigurálva van, az alábbi példa a ThreeDimensionalPoint
JSON-ként szerializált típust mutatja be:
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 }
Tipp.
Ne használjon JsonPolymorphicAttribute.TypeDiscriminatorPropertyName olyan tulajdonságot, amely ütközik a típushierarchiában lévő tulajdonsággal.
Ismeretlen származtatott típusok kezelése
Az ismeretlen származtatott típusok kezeléséhez az alaptípuson lévő jegyzetekkel kell engedélyeznie az ilyen támogatást. Vegye figyelembe a következő típushierarchiát:
[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
Mivel a konfiguráció nem támogatja FourDimensionalPoint
explicit módon, a példányok szerializálásának FourDimensionalPoint
BasePoint
megkísérlése futásidejű kivételt eredményez:
JsonSerializer.Serialize<BasePoint>(new FourDimensionalPoint()); // throws NotSupportedException
JsonSerializer.Serialize(Of BasePoint)(New FourDimensionalPoint()) ' throws NotSupportedException
Az alapértelmezett viselkedést az JsonUnknownDerivedTypeHandling alábbi enumerálással módosíthatja:
[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
Ahelyett, hogy visszaesik az alaptípusra, a FallBackToNearestAncestor
beállítással visszaeshet a legközelebbi deklarált származtatott típus szerződésére:
[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
Az előző példához hasonló konfigurációval a ThreeDimensionalPoint
típus szerializálva BasePoint
lesz:
// Serializes using the contract for BasePoint
JsonSerializer.Serialize<IPoint>(new ThreeDimensionalPoint());
' Serializes using the contract for BasePoint
JsonSerializer.Serialize(Of IPoint)(New ThreeDimensionalPoint())
Azonban a legközelebbi ősre visszatérve elismeri a "gyémánt" kétértelműség lehetőségét. Vegyük példaként a következő típushierarchiát:
[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
Ebben az esetben a BasePointWithTimeSeries
típus szerializálható, BasePoint
vagy IPointWithTimeSeries
mivel mindkettő közvetlen előd. Ez a kétértelműség azt eredményezi, hogy a rendszer eldobja a NotSupportedException példány BasePointWithTimeSeries
IPoint
as .
// throws NotSupportedException
JsonSerializer.Serialize<IPoint>(new BasePointWithTimeSeries());
' throws NotSupportedException
JsonSerializer.Serialize(Of IPoint)(New BasePointWithTimeSeries())
Polimorfizmus konfigurálása a szerződésmodellel
Olyan esetekben, amikor az attribútumjegyzetek nem praktikusak vagy lehetetlenek (például nagy tartománymodellek, szerelvényközi hierarchiák vagy harmadik féltől származó függőségek hierarchiái), a szerződésmodell használatával konfigurálhatja a polimorfizmust. A szerződésmodell olyan API-k készlete, amelyek a típushierarchiák polimorfizmusának konfigurálására használhatók egy egyéni DefaultJsonTypeInfoResolver alosztály létrehozásával, amely típusonként dinamikusan biztosít polimorfikus konfigurációt, ahogyan az alábbi példában látható:
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
További polimorf szerializálási részletek
- A polimorf szerializálás támogatja azokat a származtatott típusokat, amelyek kifejezetten a JsonDerivedTypeAttribute. A be nem jelentett típusok futásidejű kivételt eredményeznek. A viselkedés a tulajdonság konfigurálásával JsonPolymorphicAttribute.UnknownDerivedTypeHandling módosítható.
- A származtatott típusokban megadott polimorfikus konfigurációt nem örökli az alaptípusok polimorf konfigurációja. Az alaptípust egymástól függetlenül kell konfigurálni.
- A polimorf hierarchiák mindkét
interface
típusclass
esetében támogatottak. - A típuskriminálókat használó polimorfizmus csak olyan típushierarchiák esetében támogatott, amelyek az objektumok, gyűjtemények és szótártípusok alapértelmezett konvertereit használják.
- A polimorfizmus a metaadatokon alapuló forráslétrehozásban támogatott, a gyorsútvonalú forráslétrehozásban azonban nem.