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 WeatherForecastDerivedolduğ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 WeatherForecastvarsayalı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 objectbildirin.

    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 objecttanı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 objectolarak 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 WeatherForecastDerivediçeriyorsa:

  • Serileştirmeden WeatherForecastWithPrevious alınan JSON çıkışı içermezWindSpeed.
  • Serileştirmeden WeatherForecastWithPreviousAsObject alınan JSON çıkışı içerirWindSpeed.

serileştirmek WeatherForecastWithPreviousAsObjectiç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 Forecastsseri hale getirdiğinizde, olarak tanımlandığından WindSpeed objectyalnı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 WeatherForecastWithCityolduğ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 WeatherForecastBasevarsayalı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 WeatherForecastWithCityiç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ü WeatherForecastWithCityolarak gerçekleşmez. Bunun yerine, bir çalışma zamanı türü WeatherForecastBaseolarak 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 WeatherForecastBasetü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 WeatherForecastWithCityseri 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 $refgibi $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 FourDimensionalPointdesteğ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 BasePointseri 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 IPointseri 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.

Ayrıca bkz.