ile türetilmiş sınıfların özelliklerini seri hale getirme System.Text.Json
Bu makalede, türetilmiş sınıfların özelliklerini ad alanıyla serileştirmeyi System.Text.Json
öğreneceksiniz.
Türetilmiş sınıfların özelliklerini seri hale getirme
.NET 7 öncesi sürümlerde, System.Text.Json
polimorfik tür hiyerarşilerinin seri hale getirilmesini desteklemez . Örneğin, bir özelliğin türü bir arabirim veya soyut sınıfsa, çalışma zamanı türünün ek özellikleri olsa bile yalnızca arabirimde veya soyut sınıfta tanımlanan özellikler serileştirilir. Bu davranışın özel durumları bu bölümde açıklanmıştır. .NET 7 desteği hakkında bilgi için bkz . .NET 7'de çok biçimli serileştirme.
Örneğin, bir WeatherForecast
sınıfınız ve türetilmiş bir sınıfınız WeatherForecastDerived
olduğunu varsayalım:
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
Ve derleme zamanında yönteminin tür bağımsız değişkeninin Serialize
olduğunu WeatherForecast
varsayalım:
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)
Bu senaryoda, WindSpeed
nesne bir WeatherForecastDerived
nesne olsa weatherForecast
bile özelliği serileştirilmemiştir. Yalnızca temel sınıf özellikleri serileştirilir:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Bu davranış, türetilmiş çalışma zamanı tarafından oluşturulan bir türdeki verilerin yanlışlıkla açığa çıkmasını önlemeye yardımcı olmak için tasarlanmıştır.
Önceki örnekte türetilmiş türün özelliklerini seri hale getirmek için aşağıdaki yaklaşımlardan birini kullanın:
Çalışma zamanında türünü belirtmenize olanak tanıyan bir aşırı yükleme Serialize çağırın:
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)
Seri hale getirilecek nesneyi olarak
object
bildirin.options = new JsonSerializerOptions { WriteIndented = true }; jsonString = JsonSerializer.Serialize<object>(weatherForecast, options);
options = New JsonSerializerOptions With { .WriteIndented = True } jsonString = JsonSerializer.Serialize(Of Object)(weatherForecast1, options)
Yukarıdaki örnek senaryoda, her iki yaklaşım da özelliğin WindSpeed
JSON çıkışına eklenmesine neden olur:
{
"WindSpeed": 35,
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Önemli
Bu yaklaşımlar, bu kök nesnenin özellikleri için değil, yalnızca kök nesnenin seri hale getirilmesi için polimorfik serileştirme sağlar.
Türü olarak object
tanımlarsanız, alt düzey nesneler için çok biçimli serileştirme alabilirsiniz. Örneğin, sınıfınızın WeatherForecast
türü WeatherForecast
veya object
olarak tanımlanabilen adlı PreviousForecast
bir özelliği olduğunu varsayalım:
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
özelliği bir PreviousForecast
örneği WeatherForecastDerived
içeriyorsa:
- Serileştirmeden
WeatherForecastWithPrevious
alınan JSON çıkışı içermezWindSpeed
. - Serileştirmeden
WeatherForecastWithPreviousAsObject
alınan JSON çıkışı içerirWindSpeed
.
serileştirmek WeatherForecastWithPreviousAsObject
için çağrısı Serialize<object>
GetType
yapmak veya kök nesne türetilmiş türde olabilecek nesne olmadığından gerekli değildir. Aşağıdaki kod örneği veya GetType
öğesini çağırmazSerialize<object>
:
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject, options);
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject1, options)
Yukarıdaki kod doğru şekilde seri hale getirmektedir 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"
}
}
Arabirimlerle çalışan özellikleri object
tanımlama yaklaşımıyla aynı yaklaşım. Aşağıdaki arabirime ve uygulamaya sahip olduğunuzu ve bir sınıfı uygulama örnekleri içeren özelliklerle seri hale getirmek istediğinizi varsayalım:
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
örneğini Forecasts
seri hale getirdiğinizde, olarak tanımlandığından WindSpeed
object
yalnızca Tuesday
Tuesday
özelliğini gösterir:
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)
Aşağıdaki örnekte, önceki koddan elde edilen JSON gösterilmektedir:
{
"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
}
}
Not
Bu makale seri durumdan çıkarmayla değil seri hale getirmeyle ilgili. .NET 7 öncesi sürümlerde polimorfik seri durumdan çıkarma desteklenmez, ancak geçici bir çözüm olarak, Polimorfik seri durumdan çıkarma desteği'ndeki örnek gibi özel bir dönüştürücü yazabilirsiniz. .NET 7'nin çok biçimli seri hale getirme ve seri durumdan çıkarma özelliklerini nasıl desteklediği hakkında daha fazla bilgi için bkz. .NET 7'de ile System.Text.Json türetilmiş sınıfların özelliklerini serileştirme.
.NET 7 ile başlayarak, System.Text.Json
öznitelik ek açıklamalarıyla çok biçimli tür hiyerarşi serileştirmesini ve seri durumdan kaldırmayı destekler.
Öznitelik | Açıklama |
---|---|
JsonDerivedTypeAttribute | Tür bildirimine yerleştirildiğinde, belirtilen alt türün polimorfik serileştirmeye kabul edilmesi gerektiğini belirtir. Ayrıca bir tür ayrıştırıcısı belirtme özelliğini de kullanıma sunar. |
JsonPolymorphicAttribute | Bir tür bildirimine yerleştirildiğinde, türün çok biçimli olarak serileştirilmesi gerektiğini gösterir. Ayrıca, bu tür için çok biçimli serileştirme ve seri durumdan çıkarma yapılandırmaya yönelik çeşitli seçenekleri de kullanıma sunar. |
Örneğin, bir WeatherForecastBase
sınıfınız ve türetilmiş bir sınıfınız WeatherForecastWithCity
olduğunu varsayalım:
[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
Ve derleme zamanında yönteminin tür bağımsız değişkeninin Serialize<TValue>
olduğunu WeatherForecastBase
varsayalım:
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecastBase>(weatherForecastBase, options);
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(WeatherForecastBase, options)
Bu senaryoda, City
nesne aslında bir WeatherForecastWithCity
nesne olduğundan weatherForecastBase
özelliği seri hale getirilir. Bu yapılandırma, özellikle çalışma zamanı türü olduğunda WeatherForecastWithCity
için WeatherForecastBase
çok biçimli serileştirmeyi etkinleştirir:
{
"City": "Milwaukee",
"Date": "2022-09-26T00:00:00-05:00",
"TemperatureCelsius": 15,
"Summary": "Cool"
}
Yükün desteklendiği gibi WeatherForecastBase
yuvarlanması destekleniyor olsa da, çalışma zamanı türü WeatherForecastWithCity
olarak gerçekleşmez. Bunun yerine, bir çalışma zamanı türü WeatherForecastBase
olarak gerçekleştirilmesi gerekir:
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
Aşağıdaki bölümde, türetilmiş türün yuvarlama özelliğini etkinleştirmek için meta verilerin nasıl ekleneceği açıklanmaktadır.
Polimorfik tip ayrımcıları
Polimorfik seri durumdan çıkarma özelliğini etkinleştirmek için türetilen sınıf için bir tür ayrıştırıcısı belirtmeniz gerekir:
[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
Eklenen meta verilerle, özellikle de tür ayrıştırıcısıyla, seri hale getirici yükü temel türünden WeatherForecastBase
tür olarak seri hale getirebilir ve seri durumdan WeatherForecastWithCity
çıkarabilir. Serileştirme, tür ayrıştırıcı meta verileriyle birlikte JSON yayar:
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"
' }
Tür ayrıştırıcısı ile seri hale getirici yükü polimorfik olarak WeatherForecastWithCity
seri durumdan çıkarabilir:
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
Not
Varsayılan olarak, $type
ayrımcı JSON nesnesinin başına yerleştirilmelidir ve $ref
gibi $id
diğer meta veri özellikleriyle birlikte gruplandırılmalıdır. Ayrıştırıcıyı JSON nesnesinin $type
ortasına yerleştiren bir dış API'deki verileri okuyorsanız olarak ayarlayın JsonSerializerOptions.AllowOutOfOrderMetadataProperties true
:
JsonSerializerOptions options = new() { AllowOutOfOrderMetadataProperties = true };
JsonSerializer.Deserialize<Base>("""{"Name":"Name","$type":"derived"}""", options);
Çok büyük JSON nesnelerinin seri durumdan çıkarma akışlarını gerçekleştirirken aşırı arabelleğe alma (ve bellek dışı hatalara) neden olabileceğinden bu bayrağı etkinleştirirken dikkatli olun.
Tür ayrıştırıcı biçimlerini karıştırma ve eşleştirme
Tür ayrıştırıcı tanımlayıcıları veya int
formlarında string
geçerlidir, bu nedenle aşağıdakiler geçerlidir:
[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, tür ayrıştırıcı yapılandırmalarını karıştırmayı ve eşleştirmeyi desteklese de önerilmez. Genel öneri, tüm string
tür ayrımcılarını, tüm int
tür ayrımcılarını veya hiç ayrımcı kullanmamaktır. Aşağıdaki örnek, tür ayrıştırıcı yapılandırmalarının nasıl karıştırılıp eşleştirilip eşleştirilip eşleştirileceğini gösterir:
[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
Yukarıdaki örnekte türün BasePoint
tür ayrıştırıcısı yoktur, türün ThreeDimensionalPoint
tür int
ayrıştırıcısı ve FourDimensionalPoint
türü ayrıştırıcısı vardır string
.
Önemli
Polimorfik serileştirmenin çalışması için seri hale getirilmiş değerin türü, polimorfik taban türüne ait olmalıdır. Buna kök düzeyi değerleri serileştirilirken genel tür parametresi olarak, bildirilen serileştirilmiş özelliklerin türü olarak veya serileştirilmiş koleksiyonlardaki koleksiyon öğesi olarak temel türün kullanılması dahildir.
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
Tür ayrıştırıcı adını özelleştirme
Tür ayrıştırıcısının varsayılan özellik adıdır $type
. Özellik adını özelleştirmek için aşağıdaki örnekte gösterildiği gibi öğesini kullanın 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
Yukarıdaki kodda JsonPolymorphic
özniteliği değerini yapılandırıyor TypeDiscriminatorPropertyName
"$discriminator"
. Tür ayrıştırıcı adı yapılandırıldığında, aşağıdaki örnekte JSON olarak seri hale getirilmiş tür gösterilir 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 }
İpucu
Tür hiyerarşinizdeki bir JsonPolymorphicAttribute.TypeDiscriminatorPropertyName özellik ile çakişen bir kullanmaktan kaçının.
Bilinmeyen türetilmiş türleri işleme
Bilinmeyen türetilmiş türleri işlemek için temel türdeki bir ek açıklamayı kullanarak bu tür desteği kabul etmeniz gerekir. Aşağıdaki tür hiyerarşisini göz önünde bulundurun:
[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
Yapılandırma açıkça için FourDimensionalPoint
desteğini kabul etmediğinden, örneğini FourDimensionalPoint
BasePoint
seri hale getirme girişimi bir çalışma zamanı özel durumuyla sonuçlanır:
JsonSerializer.Serialize<BasePoint>(new FourDimensionalPoint()); // throws NotSupportedException
JsonSerializer.Serialize(Of BasePoint)(New FourDimensionalPoint()) ' throws NotSupportedException
Aşağıdaki gibi belirtilebilen sabit listesi kullanarak JsonUnknownDerivedTypeHandling varsayılan davranışı değiştirebilirsiniz:
[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
Temel türe geri dönmek yerine, en yakın bildirilen türetilmiş türün sözleşmesine geri dönmek için ayarını kullanabilirsiniz 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
Yukarıdaki örneğe benzer bir yapılandırmayla ThreeDimensionalPoint
, tür olarak BasePoint
seri hale getirilir:
// Serializes using the contract for BasePoint
JsonSerializer.Serialize<IPoint>(new ThreeDimensionalPoint());
' Serializes using the contract for BasePoint
JsonSerializer.Serialize(Of IPoint)(New ThreeDimensionalPoint())
Ancak, en yakın üste geri düşmek "elmas" belirsizlik olasılığını kabul eder. Örnek olarak aşağıdaki tür hiyerarşisini göz önünde bulundurun:
[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
Bu durumda, BasePointWithTimeSeries
türü ya da BasePoint
IPointWithTimeSeries
her ikisi de doğrudan ataları olduğundan seri hale getirilebilir. Bu belirsizlik, örneğini NotSupportedException BasePointWithTimeSeries
olarak IPoint
seri hale getirme girişiminde bulunulmasına neden olur.
// throws NotSupportedException
JsonSerializer.Serialize<IPoint>(new BasePointWithTimeSeries());
' throws NotSupportedException
JsonSerializer.Serialize(Of IPoint)(New BasePointWithTimeSeries())
Sözleşme modeliyle çok biçimliliği yapılandırma
Çok biçimliliği yapılandırmak için öznitelik ek açıklamalarının pratik olmadığı veya imkansız olduğu kullanım örnekleri (büyük etki alanı modelleri, çapraz derleme hiyerarşileri veya üçüncü taraf bağımlılıklarındaki hiyerarşiler gibi) için sözleşme modelini kullanın. Sözleşme modeli, aşağıdaki örnekte gösterildiği gibi tür başına dinamik olarak polimorfik yapılandırma sağlayan özel DefaultJsonTypeInfoResolver bir alt sınıf oluşturarak tür hiyerarşisinde çok biçimliliği yapılandırmak için kullanılabilecek bir API kümesidir:
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
Ek polimorfik serileştirme ayrıntıları
- Polimorfik serileştirme, aracılığıyla JsonDerivedTypeAttributeaçıkça kabul edilen türetilmiş türleri destekler. Bildirilmeyen türler bir çalışma zamanı özel durumuyla sonuçlanır. Özelliği yapılandırılarak JsonPolymorphicAttribute.UnknownDerivedTypeHandling davranış değiştirilebilir.
- Türetilmiş türlerde belirtilen polimorfik yapılandırma, temel türlerdeki polimorfik yapılandırma tarafından devralınmıyor. Temel türün bağımsız olarak yapılandırılması gerekir.
- Hem hem de
interface
class
türleri için polimorfik hiyerarşiler desteklenir. - Tür ayrımcılarını kullanan polimorfizm yalnızca nesneler, koleksiyonlar ve sözlük türleri için varsayılan dönüştürücüleri kullanan tür hiyerarşileri için desteklenir.
- Çok biçimlilik meta veri tabanlı kaynak oluşturmada desteklenir, ancak hızlı yol kaynak oluşturmada desteklenmez.