.NET'te JSON serileştirme (hazır hale getirme) için özel dönüştürücüler yazma
Bu makalede, ad alanı içinde sağlanan JSON serileştirme sınıfları için özel dönüştürücüler oluşturma hakkında bilgi System.Text.Json verilmektedir. 'ye giriş için System.Text.Json bkz. .NET'te JSON'u seri hale getirme ve seriden seriden seriden serileştirme.
Dönüştürücü, bir nesneyi veya değeri JSON'a ve JSON'dan dönüştüren bir sınıftır. Ad System.Text.Json alanı, Çoğu ilkel tür için JavaScript ilkelleri ile eşlene yerleşik dönüştürücülere sahiptir. Özel dönüştürücüler yazabilir:
- Yerleşik bir dönüştürücünün varsayılan davranışını geçersiz kılmak için. Örneğin, değerlerin
DateTimeaa/d/yyyy biçimiyle temsil ednerek temsili yapmak istiyor olabilir. VARSAYıLAN olarak, RFC 3339 profili de dahil olmak üzere ISO 8601-1:2019 de destekler. Daha fazla bilgi için bkz. içinde DateTime ve DateTimeOffset desteği. System.Text.Json - Özel bir değer türünü desteklemek için. Örneğin,
PhoneNumberbir yapı.
Ayrıca, geçerli sürümde yer alan işlevlerle özelleştirmek System.Text.Json veya genişletmek için özel dönüştürücüler de yazabilir. Aşağıdaki senaryolar bu makalenin devamlarında ele almaktadır:
Özel bir dönüştürücü için yazacak kodda, yeni örneklerin kullanımına neden olan önemli performans cezasını JsonSerializerOptions da biliyorsanız. Daha fazla bilgi için bkz. JsonSerializerOptions örneklerini yeniden kullanma.
Visual Basic özel dönüştürücüler yazmak için kullanılamaz, ancak C# kitaplıklarında uygulanan dönüştürücüleri çağırabilir. Daha fazla bilgi için bkz. Visual Basic..
Özel dönüştürücü desenleri
Özel dönüştürücü oluşturmak için iki desen vardır: temel desen ve fabrika düzeni. Fabrika düzeni, türü veya açık genel türler ile çalışan Enum dönüştürücülere yöneliktir. Temel desen, genel olmayan ve kapalı genel türler içindir. Örneğin, aşağıdaki türler için dönüştürücüler fabrika desenini gerektirir:
Temel düzen tarafından işlebilir türlere bazı örnekler şunlardır:
Temel desen, tek bir türü işlebilir bir sınıf oluşturur. Fabrika düzeni, çalışma zamanında belirli bir türün gerekli olduğunu belirleyen ve uygun dönüştürücüyü dinamik olarak oluşturan bir sınıf oluşturur.
Örnek temel dönüştürücü
Aşağıdaki örnek, mevcut bir veri türü için varsayılan serileştirmeyi geçersiz kleyen bir dönüştürücüyü içerir. Dönüştürücü, özellikler için mm/dd/yyyy biçimini DateTimeOffset kullanır.
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class DateTimeOffsetJsonConverter : JsonConverter<DateTimeOffset>
{
public override DateTimeOffset Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
DateTimeOffset.ParseExact(reader.GetString(),
"MM/dd/yyyy", CultureInfo.InvariantCulture);
public override void Write(
Utf8JsonWriter writer,
DateTimeOffset dateTimeValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(dateTimeValue.ToString(
"MM/dd/yyyy", CultureInfo.InvariantCulture));
}
}
Örnek fabrika deseni dönüştürücüsü
Aşağıdaki kod, ile çalışan özel bir dönüştürücüyü Dictionary<Enum,TValue> gösterir. İlk genel tür parametresi ve ikincisi açık olduğundan kod Enum fabrika desenini izler. yöntemi CanConvert true yalnızca, Dictionary ilki bir tür olan iki genel parametreye sahip bir için Enum döndürür. İç dönüştürücü, için çalışma zamanında sağlanan türü işlemek için mevcut bir dönüştürücü TValue alır.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class DictionaryTKeyEnumTValueConverter : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
if (typeToConvert.GetGenericTypeDefinition() != typeof(Dictionary<,>))
{
return false;
}
return typeToConvert.GetGenericArguments()[0].IsEnum;
}
public override JsonConverter CreateConverter(
Type type,
JsonSerializerOptions options)
{
Type keyType = type.GetGenericArguments()[0];
Type valueType = type.GetGenericArguments()[1];
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(DictionaryEnumConverterInner<,>).MakeGenericType(
new Type[] { keyType, valueType }),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: new object[] { options },
culture: null);
return converter;
}
private class DictionaryEnumConverterInner<TKey, TValue> :
JsonConverter<Dictionary<TKey, TValue>> where TKey : struct, Enum
{
private readonly JsonConverter<TValue> _valueConverter;
private readonly Type _keyType;
private readonly Type _valueType;
public DictionaryEnumConverterInner(JsonSerializerOptions options)
{
// For performance, use the existing converter if available.
_valueConverter = (JsonConverter<TValue>)options
.GetConverter(typeof(TValue));
// Cache the key and value types.
_keyType = typeof(TKey);
_valueType = typeof(TValue);
}
public override Dictionary<TKey, TValue> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
var dictionary = new Dictionary<TKey, TValue>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return dictionary;
}
// Get the key.
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
string propertyName = reader.GetString();
// For performance, parse with ignoreCase:false first.
if (!Enum.TryParse(propertyName, ignoreCase: false, out TKey key) &&
!Enum.TryParse(propertyName, ignoreCase: true, out key))
{
throw new JsonException(
$"Unable to convert \"{propertyName}\" to Enum \"{_keyType}\".");
}
// Get the value.
TValue value;
if (_valueConverter != null)
{
reader.Read();
value = _valueConverter.Read(ref reader, _valueType, options);
}
else
{
value = JsonSerializer.Deserialize<TValue>(ref reader, options);
}
// Add to dictionary.
dictionary.Add(key, value);
}
throw new JsonException();
}
public override void Write(
Utf8JsonWriter writer,
Dictionary<TKey, TValue> dictionary,
JsonSerializerOptions options)
{
writer.WriteStartObject();
foreach ((TKey key, TValue value) in dictionary)
{
var propertyName = key.ToString();
writer.WritePropertyName
(options.PropertyNamingPolicy?.ConvertName(propertyName) ?? propertyName);
if (_valueConverter != null)
{
_valueConverter.Write(writer, value, options);
}
else
{
JsonSerializer.Serialize(writer, value, options);
}
}
writer.WriteEndObject();
}
}
}
}
Yukarıdaki kod, bu makalenin devamlarında dize olmayan anahtar içeren Destek Sözlüğü'ne gösterilen kodla aynıdır.
Temel deseni izleme adımları
Aşağıdaki adımlarda, temel desene göre bir dönüştürücünün nasıl oluşturularak oluşturul açık bir şekilde gerçekleştirebilirsiniz:
- türünden türetilen JsonConverter<T> bir
Tsınıf oluşturun seri hale getirilecek ve seriden kaldırılan tür. - Gelen
ReadJSON'u deserialize etmek ve türüne dönüştürmek için yöntemini geçersizTkılın. Utf8JsonReaderJSON'u okumak için yöntemine geçirilen yöntemini kullanın. Seri hale getirici geçerli JSON kapsamı için tüm verileri geçtiğinden kısmi verileri işleme konusunda endişelenmenize gerek yok. Bu nedenle, veya çağrısı yapmak veya Skip TrySkip döndüren doğrulamak gerekli Readtruedeğildir. - türünde
Writegelen nesneyi serileştirmek için yöntemini geçersizTkılın. Utf8JsonWriterJSON yazmak için yöntemine geçirilen kullanın. - Yöntemi yalnızca
CanConvertgerekirse geçersiz kılın. Dönüştürülecek türtruetüründe olduğunda varsayılan uygulamaTdöndürür. Bu nedenle, yalnızca türü destekleyenTdönüştürücülerin bu yöntemi geçersiz kılması gerek değildir. Bu yöntemi geçersiz kılması gereken bir dönüştürücü örneği için bu makalenin ilerleyen kısımlarında yer alan çok biçimli deserialization bölümüne bakın.
Yerleşik dönüştürücüler kaynak koduna özel dönüştürücüler yazmaya yönelik başvuru uygulamaları olarak başvurabilirsiniz.
Fabrika desenini izleme adımları
Aşağıdaki adımlarda, fabrika desenini kullanarak bir dönüştürücünün nasıl oluşturularak oluşturul açık bir şekilde gerçekleştirebilirsiniz:
- 'den türeten bir sınıf JsonConverterFactory oluşturun.
- Dönüştürülecek
CanConverttür, dönüştürücünün işleyene bir tür olduğunda true olarak dönmek için yöntemini geçersiz kılın. Örneğin, dönüştürücü için ise yalnızcaList<T>, veList<int>'iList<string>List<DateTime>işebilir. - Çalışma zamanında sağlanan tür dönüştürmeyi işecek bir dönüştürücü sınıfının örneğini
CreateConverterdönmek için yöntemini geçersiz kılın. - Yönteminin örneklettir
CreateConverterolduğu dönüştürücü sınıfını oluşturun.
Bir nesneyi dizeye ve dizeden dönüştüren kod tüm türler için aynı olduğundan, açık genel türler için fabrika deseni gereklidir. Açık genel türe (örneğin) bir dönüştürücünün, perde arkasında kapalı genel tür ( , gibi) için bir dönüştürücü List<T> List<DateTime> oluşturması gerekir. Dönüştürücünün işley diğer kapalı genel türlerini işlemek için kod yazılmıştır.
Tür, açık genel türe benzer: için bir dönüştürücünün arkalarında belirli bir ( , örneğin) için bir dönüştürücü Enum Enum Enum WeekdaysEnum oluşturması gerekir.
yönteminde Utf8JsonReader Read kullanımı
Dönüştürücüm bir JSON nesnesini dönüştürecekse, yöntemi başladığında Utf8JsonReader başlangıç nesne belirteci üzerinde Read konumlanacak. Ardından bu nesnede bulunan tüm belirteçleri okumalı ve okuyucunun karşılık gelen son nesne belirtecinde bulunduğu yönteminden çıkabilirsiniz. Nesnenin sonunun ötesini okursanız veya karşılık gelen uç belirteci ulaşmadan önce durursanız, şunları belirten bir JsonException özel durum alırsanız:
'ConverterName' dönüştürücüsü çok fazla veya yeterli değil.
Bir örnek için, önceki fabrika deseni örnek dönüştürücüye bakın. yöntemi, Read okuyucunun bir başlangıç nesnesi belirtec üzerinde konumlarını doğrular. Sonraki uç nesne belirtec üzerinde konumlandırılana kadar okur. Nesne içinde bir nesneyi belirten müdahaleye neden olan başlangıç nesnesi belirteci olmadığını için bir sonraki uç nesne belirteci üzerinde durur. Bir diziyi dönüştürürken başlangıç belirteci ve bitiş belirteci ile ilgili aynı kural uygulanır. Örnek için bu makalenin Stack<T> devamlarında yer alan örnek dönüştürücüye bakın.
Hata işleme
Seri hale getirici, ve özel durum türleri için özel işleme JsonException NotSupportedException sağlar.
JsonException
İleti olmadan oluşturursanız seri hale getirici, JSON'un hataya neden olan kısmının JsonException yolunu içeren bir ileti oluşturur. Örneğin, deyimi aşağıdaki throw new JsonException() örnekte olduğu gibi bir hata iletisi üretir:
Unhandled exception. System.Text.Json.JsonException:
The JSON value could not be converted to System.Object.
Path: $.Date | LineNumber: 1 | BytePositionInLine: 37.
Bir ileti sağlarsanız (örneğin, ), seri hale getirici hala throw new JsonException("Error occurred") Path , ve özelliklerini LineNumber BytePositionInLine ayarlar.
Notsupportedexception
bir NotSupportedException atarsanız, iletide her zaman yol bilgilerini alırsınız. Bir ileti sağlarsanız yol bilgileri iletiye eklenir. Örneğin, deyimi aşağıdaki throw new NotSupportedException("Error occurred.") örnekte olduğu gibi bir hata iletisi üretir:
Error occurred. The unsupported member type is located on type
'System.Collections.Generic.Dictionary`2[Samples.SummaryWords,System.Int32]'.
Path: $.TemperatureRanges | LineNumber: 4 | BytePositionInLine: 24
Hangi özel durum türü ne zaman at gerekir?
JSON yükü, deserialized türü için geçerli değil belirteçler içerdiğinde, bir JsonException at.
Belirli türlerin izinlerini geri almak istediğiniz durumlarda bir NotSupportedException atarak. Bu özel durum, seri hale getiricinin, desteklenen türler için otomatik olarak ne atıyor olduğudur. Örneğin, güvenlik nedenleriyle desteklanmaz, bu nedenle, bunu bir ile sonuçlandırarak, bu girişimin bir System.Type ile NotSupportedException sonuçlanmaz.
Gerektiğinde diğer özel durumları da atabilirsiniz ancak bunlar JSON yol bilgilerini otomatik olarak dahil etmemektedir.
Özel dönüştürücü kaydetme
ve yöntemlerinin bunu kullanması için Serialize özel bir Deserialize dönüştürücüyü kaydetme. Aşağıdaki yaklaşımlardan birini seçin:
- Koleksiyona Converter sınıfının bir örneğini ekleyin JsonSerializerOptions.Converters .
- Özel dönüştürücü gerektiren özelliklere [Jsonconverter] özniteliğini uygulayın.
- [Jsonconverter] özniteliğini bir sınıfa veya özel bir değer türünü temsil eden bir yapıya uygulayın.
Kayıt örneği-dönüştürücüler koleksiyonu
Aşağıda, DateTimeOffsetJsonConverter türü özellikler için varsayılan değer veren bir örnek verilmiştir DateTimeOffset :
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Converters =
{
new DateTimeOffsetJsonConverter()
}
};
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
Aşağıdaki türde bir örneği serileştirdiğinizi varsayın:
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
Özel dönüştürücünün kullanıldığını gösteren bir JSON çıkışı örneği aşağıda verilmiştir:
{
"Date": "08/01/2019",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Aşağıdaki kod özel dönüştürücüyü kullanarak seri durumdan çıkarmak için aynı yaklaşımı kullanır DateTimeOffset :
var deserializeOptions = new JsonSerializerOptions();
deserializeOptions.Converters.Add(new DateTimeOffsetJsonConverter());
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, deserializeOptions);
Kayıt örneği-[JsonConverter] bir özellikte
Aşağıdaki kod, özelliği için özel bir dönüştürücü seçer Date :
public class WeatherForecastWithConverterAttribute
{
[JsonConverter(typeof(DateTimeOffsetJsonConverter))]
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
Seri hale getirilecek kod şunu kullanılmasını WeatherForecastWithConverterAttribute gerektirmez JsonSerializeOptions.Converters :
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
Seri durumdan çıkarılacak kod ayrıca kullanımını gerektirmez Converters :
weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithConverterAttribute>(jsonString);
Kayıt örneği-[JsonConverter] bir tür üzerinde
Bir struct oluşturan ve özniteliği uygulayan kod aşağıda verilmiştir [JsonConverter] :
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
[JsonConverter(typeof(TemperatureConverter))]
public struct Temperature
{
public Temperature(int degrees, bool celsius)
{
Degrees = degrees;
IsCelsius = celsius;
}
public int Degrees { get; }
public bool IsCelsius { get; }
public bool IsFahrenheit => !IsCelsius;
public override string ToString() =>
$"{Degrees}{(IsCelsius ? "C" : "F")}";
public static Temperature Parse(string input)
{
int degrees = int.Parse(input.Substring(0, input.Length - 1));
bool celsius = input.Substring(input.Length - 1) == "C";
return new Temperature(degrees, celsius);
}
}
}
Önceki yapı için özel dönüştürücü aşağıda verilmiştir:
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class TemperatureConverter : JsonConverter<Temperature>
{
public override Temperature Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
Temperature.Parse(reader.GetString());
public override void Write(
Utf8JsonWriter writer,
Temperature temperature,
JsonSerializerOptions options) =>
writer.WriteStringValue(temperature.ToString());
}
}
[JsonConverter]Yapı üzerindeki özniteliği özel dönüştürücüyü türü özellikler için varsayılan olarak kaydeder Temperature . Dönüştürücü, TemperatureCelsius seri hale getirmek veya serisini kaldırmak için aşağıdaki türün özelliğinde otomatik olarak kullanılır:
public class WeatherForecastWithTemperatureStruct
{
public DateTimeOffset Date { get; set; }
public Temperature TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
Dönüştürücü kayıt önceliği
Serileştirme veya seri durumundan çıkarma sırasında, en yüksek öncelikten en düşüğe doğru listelenen her bir JSON öğesi için bir dönüştürücü seçilir:
[JsonConverter]bir özelliğe uygulandı.- Koleksiyona eklenen bir dönüştürücü
Converters. [JsonConverter]özel bir değer türüne veya POCO 'a uygulandı.
Bir tür için birden çok özel dönüştürücü Converters koleksiyonda kayıtlıysa, için true döndüren ilk dönüştürücü CanConvert kullanılır.
Yalnızca uygulanabilir özel dönüştürücü kayıtlı değilse, yerleşik bir dönüştürücü seçilir.
Yaygın senaryolar için dönüştürücü örnekleri
Aşağıdaki bölümlerde, yerleşik işlevlerin sağlamadığı bazı yaygın senaryolar ele alan dönüştürücü örnekleri sağlanmaktadır.
Örnek dönüştürücü için DataTable bkz. Desteklenen koleksiyon türleri.
Çıkartılan türlerin nesne özelliklerine serisini kaldırma
Türünde bir özelliğe seri durumdan çıkarılırken object bir JsonElement nesne oluşturulur. Bunun nedeni, seri hale getiricinin oluşturulacak CLR türünü bilmeyeceği ve tahmin etmeye çalışmayın. Örneğin, bir JSON özelliğinde "true" varsa, seri hale getirici değerin bir olduğunu Boolean ve bir öğede "01/01/2019" varsa, seri hale getiricinin bir olduğunu çıkarmaz DateTime .
Tür çıkarımı yanlış olabilir. Seri hale getirici, ondalık noktası olmayan bir JSON numarasını ayrıştırır long . Bu, değerin başlangıçta veya olarak seri hale getirilmediği durumlarda Aralık dışı sorunlara yol açabilir ulong BigInteger . doubleSayı ilk olarak bir olarak seri hale getirilemediği takdirde, ondalık noktası olan bir sayının ayrıştırmasında duyarlık kaybolabilir decimal .
Tür çıkarımı gerektiren senaryolar için aşağıdaki kod, özellikler için özel bir dönüştürücü gösterir object . Kod dönüştürür:
truevefalseiçinBoolean- Ondalık olmayan sayılar
long - Ondalık sayı olan sayılar
double - Tarihler
DateTime - Dizeler
string - Diğer her şey
JsonElement
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace CustomConverterInferredTypesToObject
{
public class ObjectToInferredTypesConverter : JsonConverter<object>
{
public override object Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) => reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Number when reader.TryGetInt64(out long l) => l,
JsonTokenType.Number => reader.GetDouble(),
JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => datetime,
JsonTokenType.String => reader.GetString(),
_ => JsonDocument.ParseValue(ref reader).RootElement.Clone()
};
public override void Write(
Utf8JsonWriter writer,
object objectToWrite,
JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
}
public class WeatherForecast
{
public object Date { get; set; }
public object TemperatureCelsius { get; set; }
public object Summary { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = @"{
""Date"": ""2019-08-01T00:00:00-07:00"",
""TemperatureCelsius"": 25,
""Summary"": ""Hot""
}";
WeatherForecast weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);
Console.WriteLine($"Type of Date property no converter = {weatherForecast.Date.GetType()}");
var options = new JsonSerializerOptions();
options.WriteIndented = true;
options.Converters.Add(new ObjectToInferredTypesConverter());
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, options);
Console.WriteLine($"Type of Date property with converter = {weatherForecast.Date.GetType()}");
Console.WriteLine(JsonSerializer.Serialize(weatherForecast, options));
}
}
}
// Produces output like the following example:
//
//Type of Date property no converter = System.Text.Json.JsonElement
//Type of Date property with converter = System.DateTime
//{
// "Date": "2019-08-01T00:00:00-07:00",
// "TemperatureCelsius": 25,
// "Summary": "Hot"
//}
Örnekte, dönüştürücü kodu ve WeatherForecast özellikleri olan bir sınıf gösterilmektedir object . MainYöntemi, WeatherForecast önce dönüştürücüyü kullanmadan, sonra dönüştürücüyü kullanarak bir JSON dizesini bir örneğe seri hale getirir. Konsol çıktısı, özelliği için çalışma zamanı türü olan dönüştürücü olmadan, Date JsonElement çalışma zamanı türünün olduğunu gösterir DateTime .
Ad alanındaki birim testleri klasörü , System.Text.Json.Serialization özellikleri seri durumdan çıkarmayı işleyen özel dönüştürücülerin daha fazla örneklerine sahiptir object .
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class ObjectToInferredTypesConverter
: JsonConverter<object>
{
public override object Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) => reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Number when reader.TryGetInt64(out long l) => l,
JsonTokenType.Number => reader.GetDouble(),
JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => datetime,
JsonTokenType.String => reader.GetString(),
_ => JsonDocument.ParseValue(ref reader).RootElement.Clone()
};
public override void Write(
Utf8JsonWriter writer,
object objectToWrite,
JsonSerializerOptions options) =>
throw new InvalidOperationException("Should not get here.");
}
}
Aşağıdaki kod dönüştürücüyü kaydeder:
var deserializeOptions = new JsonSerializerOptions
{
Converters =
{
new ObjectToInferredTypesConverter()
}
};
Özelliklere sahip örnek bir tür aşağıda verilmiştir object :
public class WeatherForecastWithObjectProperties
{
public object Date { get; set; }
public object TemperatureCelsius { get; set; }
public object Summary { get; set; }
}
Seri durumdan çıkarılacak aşağıdaki JSON örneği,, ve olarak seri durumdan çıkarılacak değerler DateTime içerir long string :
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot",
}
Özel dönüştürücü olmadan, seri durumdan çıkarma JsonElement her özelliğe bir koyar.
Ad alanındaki birim testleri klasörü , System.Text.Json.Serialization özellikleri seri durumdan çıkarmayı işleyen özel dönüştürücülerin daha fazla örneklerine sahiptir object .
Dize olmayan anahtarla destek sözlüğü
Sözlük koleksiyonları için yerleşik destek Dictionary<string, TValue> . Diğer bir deyişle, anahtar bir dize olmalıdır. Anahtar olarak bir tamsayı veya başka tür içeren bir sözlüğü desteklemek için özel bir dönüştürücü gerekir.
Aşağıdaki kod ile birlikte çalışarak özel bir dönüştürücüyü göstermektedir Dictionary<Enum,TValue> :
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class DictionaryTKeyEnumTValueConverter : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
if (typeToConvert.GetGenericTypeDefinition() != typeof(Dictionary<,>))
{
return false;
}
return typeToConvert.GetGenericArguments()[0].IsEnum;
}
public override JsonConverter CreateConverter(
Type type,
JsonSerializerOptions options)
{
Type keyType = type.GetGenericArguments()[0];
Type valueType = type.GetGenericArguments()[1];
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(DictionaryEnumConverterInner<,>).MakeGenericType(
new Type[] { keyType, valueType }),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: new object[] { options },
culture: null);
return converter;
}
private class DictionaryEnumConverterInner<TKey, TValue> :
JsonConverter<Dictionary<TKey, TValue>> where TKey : struct, Enum
{
private readonly JsonConverter<TValue> _valueConverter;
private readonly Type _keyType;
private readonly Type _valueType;
public DictionaryEnumConverterInner(JsonSerializerOptions options)
{
// For performance, use the existing converter if available.
_valueConverter = (JsonConverter<TValue>)options
.GetConverter(typeof(TValue));
// Cache the key and value types.
_keyType = typeof(TKey);
_valueType = typeof(TValue);
}
public override Dictionary<TKey, TValue> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
var dictionary = new Dictionary<TKey, TValue>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return dictionary;
}
// Get the key.
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
string propertyName = reader.GetString();
// For performance, parse with ignoreCase:false first.
if (!Enum.TryParse(propertyName, ignoreCase: false, out TKey key) &&
!Enum.TryParse(propertyName, ignoreCase: true, out key))
{
throw new JsonException(
$"Unable to convert \"{propertyName}\" to Enum \"{_keyType}\".");
}
// Get the value.
TValue value;
if (_valueConverter != null)
{
reader.Read();
value = _valueConverter.Read(ref reader, _valueType, options);
}
else
{
value = JsonSerializer.Deserialize<TValue>(ref reader, options);
}
// Add to dictionary.
dictionary.Add(key, value);
}
throw new JsonException();
}
public override void Write(
Utf8JsonWriter writer,
Dictionary<TKey, TValue> dictionary,
JsonSerializerOptions options)
{
writer.WriteStartObject();
foreach ((TKey key, TValue value) in dictionary)
{
var propertyName = key.ToString();
writer.WritePropertyName
(options.PropertyNamingPolicy?.ConvertName(propertyName) ?? propertyName);
if (_valueConverter != null)
{
_valueConverter.Write(writer, value, options);
}
else
{
JsonSerializer.Serialize(writer, value, options);
}
}
writer.WriteEndObject();
}
}
}
}
Aşağıdaki kod dönüştürücüyü kaydeder:
var serializeOptions = new JsonSerializerOptions();
serializeOptions.Converters.Add(new DictionaryTKeyEnumTValueConverter());
Dönüştürücü, aşağıdakileri TemperatureRanges kullanan aşağıdaki sınıfın özelliğini seri hale getirebilirsiniz ve serisini kaldıramıyor Enum :
public class WeatherForecastWithEnumDictionary
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
public Dictionary<SummaryWordsEnum, int> TemperatureRanges { get; set; }
}
public enum SummaryWordsEnum
{
Cold, Hot
}
Seri hale getirme işleminden alınan JSON çıktısı aşağıdaki örneğe benzer şekilde görünür:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot",
"TemperatureRanges": {
"Cold": 20,
"Hot": 40
}
}
Ad alanındaki birim testleri klasörü , System.Text.Json.Serialization dize dışı anahtar sözlüklerini işleyen özel dönüştürücülere daha fazla örnek içerir.
Polimorfik serisini destekler
Yerleşik özellikler sınırlı sayıda polimorfik serileştirme sağlar, ancak hiçbir zaman serisini kaldırma desteği yoktur. Seri durumdan çıkarma özel bir dönüştürücü gerektirir.
Örneğin, Person Employee ve türetilmiş sınıflar içeren bir soyut taban sınıfınız olduğunu varsayalım Customer . Polimorfik seri kaldırma, tasarım zamanında Person , seri durumdan çıkarma hedefi olarak belirtebileceğiniz ve Customer Employee JSON 'daki nesnelerin çalışma zamanında doğru bir şekilde seri durumdan çıkarılması anlamına gelir. Seri durumdan çıkarma sırasında, JSON 'da gerekli türü tanımlayan ipuçları bulmanız gerekir. Kullanılabilir ipuçları türleri her senaryoya göre farklılık gösterir. Örneğin, bir Ayrıştırıcı özelliği kullanılabilir olabilir veya belirli bir özelliğin varlığına veya yokluğuna güvenebilirsiniz. Geçerli sürümü, çok System.Text.Json biçimli seri kaldırma senaryolarını nasıl işleyeceğinizi belirtmek için öznitelikler sağlamaz, bu nedenle özel dönüştürücüler gereklidir.
Aşağıdaki kod, temel sınıfı, iki türetilmiş sınıfı ve bunlar için özel bir dönüştürücüyü gösterir. Dönüştürücü, çok biçimli seri kaldırma işlemi yapmak için bir Ayrıştırıcı özelliği kullanır. Tür ayrıştırıcısı sınıf tanımlarında değildir, ancak serileştirme sırasında oluşturulur ve seri durumundan çıkarma sırasında okunabilir.
public class Person
{
public string Name { get; set; }
}
public class Customer : Person
{
public decimal CreditLimit { get; set; }
}
public class Employee : Person
{
public string OfficeNumber { get; set; }
}
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class PersonConverterWithTypeDiscriminator : JsonConverter<Person>
{
enum TypeDiscriminator
{
Customer = 1,
Employee = 2
}
public override bool CanConvert(Type typeToConvert) =>
typeof(Person).IsAssignableFrom(typeToConvert);
public override Person Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
reader.Read();
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
string propertyName = reader.GetString();
if (propertyName != "TypeDiscriminator")
{
throw new JsonException();
}
reader.Read();
if (reader.TokenType != JsonTokenType.Number)
{
throw new JsonException();
}
TypeDiscriminator typeDiscriminator = (TypeDiscriminator)reader.GetInt32();
Person person = typeDiscriminator switch
{
TypeDiscriminator.Customer => new Customer(),
TypeDiscriminator.Employee => new Employee(),
_ => throw new JsonException()
};
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return person;
}
if (reader.TokenType == JsonTokenType.PropertyName)
{
propertyName = reader.GetString();
reader.Read();
switch (propertyName)
{
case "CreditLimit":
decimal creditLimit = reader.GetDecimal();
((Customer)person).CreditLimit = creditLimit;
break;
case "OfficeNumber":
string officeNumber = reader.GetString();
((Employee)person).OfficeNumber = officeNumber;
break;
case "Name":
string name = reader.GetString();
person.Name = name;
break;
}
}
}
throw new JsonException();
}
public override void Write(
Utf8JsonWriter writer, Person person, JsonSerializerOptions options)
{
writer.WriteStartObject();
if (person is Customer customer)
{
writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.Customer);
writer.WriteNumber("CreditLimit", customer.CreditLimit);
}
else if (person is Employee employee)
{
writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.Employee);
writer.WriteString("OfficeNumber", employee.OfficeNumber);
}
writer.WriteString("Name", person.Name);
writer.WriteEndObject();
}
}
}
Aşağıdaki kod dönüştürücüyü kaydeder:
var serializeOptions = new JsonSerializerOptions();
serializeOptions.Converters.Add(new PersonConverterWithTypeDiscriminator());
Dönüştürücü, serileştirme için aynı dönüştürücü kullanılarak oluşturulan JSON serisini kaldıramıyor, örneğin:
[
{
"TypeDiscriminator": 1,
"CreditLimit": 10000,
"Name": "John"
},
{
"TypeDiscriminator": 2,
"OfficeNumber": "555-1234",
"Name": "Nancy"
}
]
Yukarıdaki örnekteki dönüştürücü kodu, her bir özelliği el ile okur ve yazar. Bir alternatif, çalışmanın bir Deserialize kısmını çağırmak veya yapmak için kullanılır Serialize . Bir örnek için, Bu StackOverflow gönderisiniinceleyin.
Polimorfik serisini yapmanın alternatif bir yolu
Deserialize Read Yöntemini çağırabilirsiniz:
- Örneğin bir kopyasını oluşturun
Utf8JsonReader.Utf8JsonReaderBir struct olduğundan, bu yalnızca bir atama ekstresi gerektirir. - Ayrıştırıcı belirteçlerini okumak için klonu kullanın.
DeserializeReaderİhtiyacınız olan türü öğrendikten sonra özgün örneği kullanarak çağırın.DeserializeReaderBaşlangıç nesnesi belirtecini okumak için özgün örnek hala konumlandırıldığından öğesini çağırabilirsiniz.
Bu yöntemin bir dezavantajı, dönüştürücüyü kaydeden özgün seçenekler örneğini geçiremiyoruz Deserialize . Bunun yapılması, gerekli özelliklerdeaçıklandığı gibi yığın taşmasına neden olur. Aşağıdaki örnek, Read Bu alternatifi kullanan bir yöntemi gösterir:
public override Person Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Utf8JsonReader readerClone = reader;
if (readerClone.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
readerClone.Read();
if (readerClone.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
string propertyName = readerClone.GetString();
if (propertyName != "TypeDiscriminator")
{
throw new JsonException();
}
readerClone.Read();
if (readerClone.TokenType != JsonTokenType.Number)
{
throw new JsonException();
}
TypeDiscriminator typeDiscriminator = (TypeDiscriminator)readerClone.GetInt32();
Person person = typeDiscriminator switch
{
TypeDiscriminator.Customer => JsonSerializer.Deserialize<Customer>(ref reader),
TypeDiscriminator.Employee => JsonSerializer.Deserialize<Employee>(ref reader),
_ => throw new JsonException()
};
return person;
}
Yığın için gidiş dönüş desteği<T>
Bir JSON dizesini bir nesneye serisini çıkardıysanız Stack<T> ve sonra bu nesneyi serileştirmek istiyorsanız, yığının içeriği ters sıralardır. Bu davranış, aşağıdaki türler ve arabirim için ve bunlardan türetilmiş Kullanıcı tanımlı türler için geçerlidir:
Yığın içinde orijinal sırayı koruyan serileştirme ve serisini desteklemek için özel bir dönüştürücü gereklidir.
Aşağıdaki kod, nesnelerinden ve nesnelerden gidiş dönüşü sağlayan özel bir dönüştürücüyü gösterir Stack<T> :
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class JsonConverterFactoryForStackOfT : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
=> typeToConvert.IsGenericType
&& typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>);
public override JsonConverter CreateConverter(
Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(typeToConvert.IsGenericType &&
typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>));
Type elementType = typeToConvert.GetGenericArguments()[0];
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(JsonConverterForStackOfT<>)
.MakeGenericType(new Type[] { elementType }),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: null,
culture: null)!;
return converter;
}
}
public class JsonConverterForStackOfT<T> : JsonConverter<Stack<T>>
{
public override Stack<T> Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
{
throw new JsonException();
}
reader.Read();
var elements = new Stack<T>();
while (reader.TokenType != JsonTokenType.EndArray)
{
elements.Push(JsonSerializer.Deserialize<T>(ref reader, options));
reader.Read();
}
return elements;
}
public override void Write(
Utf8JsonWriter writer, Stack<T> value, JsonSerializerOptions options)
{
writer.WriteStartArray();
var reversed = new Stack<T>(value);
foreach (T item in reversed)
{
JsonSerializer.Serialize(writer, item, options);
}
writer.WriteEndArray();
}
}
}
Aşağıdaki kod dönüştürücüyü kaydeder:
var options = new JsonSerializerOptions
{
Converters = { new JsonConverterFactoryForStackOfT() },
};
Enum dize değeri serisini kaldırma desteği
Varsayılan olarak yerleşik, JsonStringEnumConverter Numaralandırmalar için dize değerlerini serileştirme ve seri durumdan çıkarma yapabilir. Belirtilen bir adlandırma ilkesi olmadan veya adlandırma ilkesiyle birlikte çalışarak CamelCase . Snake durumu gibi diğer adlandırma ilkelerini desteklemez. bir snake case adlandırma ilkesi kullanırken enum dize değerlerine gidiş-dönüşü destekleyebilen özel dönüştürücü kodu hakkında daha fazla bilgi için, bkz. GitHub, dotnet/runtime #31619sorun.
Null değerleri işleme
Varsayılan olarak, seri hale getirici null değerlerini aşağıdaki şekilde işler:
Başvuru türleri ve Nullable<T> türleri için:
nullSerileştirme sırasında özel Dönüştürücülerine geçmez.JsonTokenType.NullSeri durumdan çıkarma sırasında özel Dönüştürücülerine geçmez.nullSeri durumdan çıkarma üzerine bir örnek döndürür.nullSerileştirme üzerinde doğrudan yazıcıya yazar.
Null yapılamayan değer türleri için:
JsonTokenType.NullSeri durumdan çıkarma sırasında özel Dönüştürücülerine geçer. (Özel dönüştürücü yoksa,JsonExceptiontür için iç dönüştürücü tarafından bir özel durum oluşturulur.)
Bu null işleme davranışı öncelikle, dönüştürücünün ek bir çağrısını atlayarak performansı iyileştirir. Ayrıca, null her Read ve Write yöntemi geçersiz kılmanın başlangıcında olup olmadığını kontrol etmek için null yapılabilir türler için dönüştürücüler zorlamaktan kaçınır.
Bir özel dönüştürücünün null bir başvuru veya değer türü için işlemesini sağlamak için, JsonConverter<T>.HandleNull true Aşağıdaki örnekte gösterildiği gibi, döndürecek şekilde geçersiz kılın:
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace CustomConverterHandleNull
{
public class Point
{
public int X { get; set; }
public int Y { get; set; }
[JsonConverter(typeof(DescriptionConverter))]
public string Description { get; set; }
}
public class DescriptionConverter : JsonConverter<string>
{
public override bool HandleNull => true;
public override string Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
reader.GetString() ?? "No description provided.";
public override void Write(
Utf8JsonWriter writer,
string value,
JsonSerializerOptions options) =>
writer.WriteStringValue(value);
}
public class Program
{
public static void Main()
{
string json = @"{""x"":1,""y"":2,""Description"":null}";
Point point = JsonSerializer.Deserialize<Point>(json);
Console.WriteLine($"Description: {point.Description}");
}
}
}
// Produces output like the following example:
//
//Description: No description provided.
Başvuruları koruma
Varsayılan olarak, başvuru verileri yalnızca veya için yapılan her çağrı için önbelleğe alınır Serialize Deserialize . Bir çağrıdan diğerine yapılan başvuruları kalıcı hale getirmek için Serialize / Deserialize , ' ReferenceResolver ın çağrı sitesinde kökünü yapın Serialize / Deserialize . Aşağıdaki kod, bu senaryo için bir örnek gösterir:
- Tür için özel bir dönüştürücü yazarsınız
Company. - Özelliği olan özelliğini el ile seri hale getirmek istemezsiniz
SupervisorEmployee. Bunu serileştiriciye atamak istiyorsunuz ve daha önce kaydettiğiniz başvuruları korumak istiyorsunuz.
EmployeeVe Company sınıfları şunlardır:
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public List<Employee> DirectReports { get; set; }
public Company Company { get; set; }
}
public class Company
{
public string Name { get; set; }
public Employee Supervisor { get; set; }
}
Dönüştürücü şuna benzer:
class CompanyConverter : JsonConverter<Company>
{
public override Company Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, Company value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteString("Name", value.Name);
writer.WritePropertyName("Supervisor");
JsonSerializer.Serialize(writer, value.Supervisor, options);
writer.WriteEndObject();
}
}
Öğesinden türetilen bir sınıf ReferenceResolver , başvuruları bir sözlükte depolar:
class MyReferenceResolver : ReferenceResolver
{
private uint _referenceCount;
private readonly Dictionary<string, object> _referenceIdToObjectMap = new ();
private readonly Dictionary<object, string> _objectToReferenceIdMap = new (ReferenceEqualityComparer.Instance);
public override void AddReference(string referenceId, object value)
{
if (!_referenceIdToObjectMap.TryAdd(referenceId, value))
{
throw new JsonException();
}
}
public override string GetReference(object value, out bool alreadyExists)
{
if (_objectToReferenceIdMap.TryGetValue(value, out string referenceId))
{
alreadyExists = true;
}
else
{
_referenceCount++;
referenceId = _referenceCount.ToString();
_objectToReferenceIdMap.Add(value, referenceId);
alreadyExists = false;
}
return referenceId;
}
public override object ResolveReference(string referenceId)
{
if (!_referenceIdToObjectMap.TryGetValue(referenceId, out object value))
{
throw new JsonException();
}
return value;
}
}
Öğesinden türetilen bir sınıf ReferenceHandler , bir örneğini tutar MyReferenceResolver ve yalnızca gerektiğinde yeni bir örnek oluşturur (Bu örnekte adlı bir yöntemde Reset ):
class MyReferenceHandler : ReferenceHandler
{
public MyReferenceHandler() => Reset();
private ReferenceResolver _rootedResolver;
public override ReferenceResolver CreateResolver() => _rootedResolver;
public void Reset() => _rootedResolver = new MyReferenceResolver();
}
Örnek kod serileştiriciyi çağırdığında, JsonSerializerOptions ReferenceHandler özelliğinin bir örneğine ayarlandığı bir örneği kullanır MyReferenceHandler . Bu kalıbı izlediğinizde, ReferenceResolver seri hale getirmeyi tamamladıktan sonra, sonsuza kadar büyümeye devam etmek için sözlüğü sıfırladığınızdan emin olun.
var options = new JsonSerializerOptions();
options.Converters.Add(new CompanyConverter());
var myReferenceHandler = new MyReferenceHandler();
options.ReferenceHandler = myReferenceHandler;
options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.WriteIndented = true;
string str = JsonSerializer.Serialize(tyler, options);
// Reset after serializing to avoid out of bounds memory growth in the resolver.
myReferenceHandler.Reset();
Yukarıdaki örnek yalnızca serileştirme amaçlıdır, ancak seri durumundan çıkarma için benzer bir yaklaşım benimsemiş olabilir.
Başvuruların nasıl korunduğu hakkında daha fazla bilgi için bu sayfanın .NET 5 sürümünebakın.
Diğer özel dönüştürücü örnekleri
' Den Newtonsoft.Json System.Text.Json geçiş , özel dönüştürücülerin ek örneklerini içerir.
Kaynak kodundaki birim testleri klasörü System.Text.Json.Serialization , gibi diğer özel dönüştürücü örneklerini içerir:
- Seri durumdan çıkarma sırasında null değeri 0 olarak dönüştüren Int32 Dönüştürücüsü
- Seri durumdan çıkarma sırasında hem dize hem de sayı değerlerine izin veren Int32 Dönüştürücüsü
- Sabit Listesi Dönüştürücüsü
- <T>Dış verileri kabul eden liste Dönüştürücüsü
- Long [] bir sayı listesi ile birlikte çalışma
Varolan bir yerleşik dönüştürücünün davranışını değiştiren bir dönüştürücü yapmanız gerekiyorsa, varolan dönüştürücünün özelleştirme için bir başlangıç noktası olarak sunmak üzere kaynak kodunu alabilirsiniz.
Ek kaynaklar
- Yerleşik dönüştürücüler için kaynak kodu
- System.Text.Json bakýþ
- JSON’u seri hale getirme ve seri halden çıkarma
- JsonSerializerOptions örneklerinin örneğini oluşturma
- Büyük/küçük harf duyarlı eşlemeyi etkinleştirme
- Özellik adlarını ve değerlerini özelleştirme
- Özellikleri yoksayma
- Geçersiz JSON’a izin verme
- Taşma JSON 'ı veya JsonElement veya JsonNode kullanın
- Başvuruları koru ve döngüsel başvuruları işle
- Sabit türler ve genel olmayan erişimciler için seri durumdan çıkarma
- Polimorfik serileştirme
- ' Den ' a geçiş Newtonsoft.JsonSystem.Text.Json
- Karakter kodlamasını özelleştirme
- DOM, Utf8JsonReader ve Utf8JsonWriter kullanma
- DateTime ve DateTimeOffset desteği
- Kaynak oluşturmayı kullanma
- Desteklenen koleksiyon türleri
- System.Text.Json API başvurusu
- System.Text.Json. Serileştirme API başvurusu