Cara menggunakan JSONOBJECT.TOSTRING pada JavaScript

Lompati ke konten utama

Browser ini sudah tidak didukung.

Mutakhirkan ke Microsoft Edge untuk memanfaatkan fitur, pembaruan keamanan, dan dukungan teknis terkini.

Cara menulis pengonversi kustom untuk serialisasi JSON (penyusunan) di .NET

  • Artikel
  • 09/29/2022
  • 25 menit untuk membaca

Dalam artikel ini

Artikel ini menunjukkan cara membuat pengonversi kustom untuk kelas serialisasi JSON yang disediakan di namespace layanan System.Text.Json. Untuk pengenalan System.Text.Json, lihat Cara membuat serialisasi dan deserialisasi JSON di .NET.

Pengonversi adalah kelas yang mengonversi objek atau nilai ke dan dari JSON. Namespace layanan System.Text.Json memiliki pengonversi bawaan untuk sebagian besar jenis primitif yang memetakan ke primitif JavaScript. Anda dapat menulis pengonversi kustom:

  • Untuk mengganti perilaku pengonversi bawaan default. Misalnya, Anda mungkin ingin nilai DateTime diwakili oleh format mm/dd/yyyy. Secara default, ISO 8601-1:2019 didukung, termasuk profil RFC 3339. Untuk informasi selengkapnya, lihat Dukungan DateTime dan DateTimeOffset di System.Text.Json.
  • Untuk mendukung jenis nilai kustom. Misalnya, struktur PhoneNumber.

Anda juga dapat menulis pengonversi kustom untuk menyesuaikan atau memperluas System.Text.Json dengan fungsionalitas yang tidak disertakan dalam rilis saat ini. Skenario berikut dibahas nanti dalam artikel ini:

  • Deserialisasi jenis yang disimpulkan ke properti objek.
  • Mendukung deserialisasi polimorfik.
  • Mendukung komunikasi dua arah untuk Stack.
  • Mendukung deserialisasi nilai string enum.
  • Menggunakan pengonversi sistem default.

  • Deserialisasi jenis yang disimpulkan ke properti objek.
  • Mendukung deserialisasi polimorfik.
  • Mendukung komunikasi dua arah untuk Stack.
  • Mendukung deserialisasi nilai string enum.

  • Deserialisasi jenis yang disimpulkan ke properti objek.
  • Mendukung Kamus dengan kunci non-string.
  • Mendukung deserialisasi polimorfik.
  • Mendukung komunikasi dua arah untuk Stack.

Dalam kode yang Anda tulis untuk pengonversi kustom, perhatikan penalti performa substansial untuk menggunakan instans JsonSerializerOptions baru. Untuk informasi selengkapnya, lihat Menggunakan kembali instans JsonSerializerOptions.

Visual Basic tidak dapat digunakan untuk menulis pengonversi kustom tetapi dapat memanggil pengonversi yang diimplementasikan di pustaka C#. Untuk informasi selengkapnya, lihat dukungan Visual Basic.

Pola pengonversi kustom

Ada dua pola untuk membuat pengonversi kustom: pola dasar dan pola pabrik. Pola pabrik adalah untuk pengonversi yang menangani jenis Enum atau generik terbuka. Pola dasarnya adalah untuk jenis generik dan non-generik tertutup. Misalnya, non-generik untuk jenis berikut memerlukan pola pabrik:

  • Dictionary
  • Enum
  • List

Beberapa contoh jenis yang dapat ditangani oleh pola dasar meliputi:

  • Dictionary
  • WeekdaysEnum
  • List
  • DateTime
  • Int32

Pola dasar menciptakan kelas yang dapat menangani satu jenis. Pola pabrik menciptakan kelas yang menentukan, pada waktu berjalan, jenis tertentu mana yang diperlukan dan secara dinamis membuat pengonversi yang sesuai.

Sampel pengonversi dasar

Sampel berikut adalah pengonversi yang menimpa serialisasi default untuk jenis data yang ada. Pengonversi menggunakan format mm/dd/yyyy untuk properti DateTimeOffset.

using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace SystemTextJsonSamples
{
    public class DateTimeOffsetJsonConverter : JsonConverter
    {
        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));
    }
}

Sampel pengonversi pola pabrik

Kode berikut menunjukkan pengonversi kustom yang berfungsi dengan Dictionary. Kode mengikuti pola pabrik karena parameter jenis generik pertama adalah Enum dan yang kedua terbuka. Metode CanConvert hanya menampilkan true untuk Dictionary dengan dua parameter generik, yang pertama adalah jenis Enum. Pengonversi dalam akan mendapatkan pengonversi yang ada untuk menangani jenis apa pun yang disediakan pada durasi untuk TValue.

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 :
            JsonConverter> where TKey : struct, Enum
        {
            private readonly JsonConverter _valueConverter;
            private readonly Type _keyType;
            private readonly Type _valueType;

            public DictionaryEnumConverterInner(JsonSerializerOptions options)
            {
                // For performance, use the existing converter if available.
                _valueConverter = (JsonConverter)options
                    .GetConverter(typeof(TValue));

                // Cache the key and value types.
                _keyType = typeof(TKey);
                _valueType = typeof(TValue);
            }

            public override Dictionary Read(
                ref Utf8JsonReader reader,
                Type typeToConvert,
                JsonSerializerOptions options)
            {
                if (reader.TokenType != JsonTokenType.StartObject)
                {
                    throw new JsonException();
                }

                var dictionary = new Dictionary();

                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(ref reader, options)!;
                    }

                    // Add to dictionary.
                    dictionary.Add(key, value);
                }

                throw new JsonException();
            }

            public override void Write(
                Utf8JsonWriter writer,
                Dictionary 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();
            }
        }
    }
}

Langkah-langkah untuk mengikuti pola dasar

Langkah-langkah berikut menjelaskan cara membuat pengonversi dengan mengikuti pola dasar:

  • Buat kelas yang berasal dari JsonConverter dengan T adalah jenis yang akan diserialisasikan dan dideserialisasi.
  • Ganti metode Read untuk mendeserialisasi JSON yang masuk dan mengonversinya menjadi jenis T. Gunakan Utf8JsonReader yang diteruskan ke metode untuk membaca JSON. Anda tidak perlu khawatir tentang penanganan data parsial, karena pembuat serialisasi meneruskan semua data untuk cakupan JSON saat ini. Jadi tidak perlu memanggil Skip atau TrySkip, atau memvalidasi bahwa Read menampilkan true.
  • Ganti metode Write untuk menserialisasi objek yang masuk jenis T. Gunakan Utf8JsonWriter yang diteruskan ke metode untuk menulis JSON.
  • Ganti metode CanConvert hanya jika perlu. Implementasi default akan menampilkan true jika jenis yang akan dikonversi berjenis T. Oleh karena itu, pengonversi yang hanya mendukung jenis T tidak perlu mengganti metode ini. Untuk contoh pengonversi yang memang perlu mengganti metode ini, lihat bagian deserialisasi polimorfik nanti dalam artikel ini.

Anda dapat merujuk ke kode sumber pengonversi bawaan sebagai implementasi referensi untuk menulis pengonversi kustom.

Langkah-langkah untuk mengikuti pola pabrik

Langkah-langkah berikut menjelaskan cara membuat pengonversi dengan mengikuti pola pabrik:

  • Buat kelas yang berasal dari JsonConverterFactory.
  • Ganti metode CanConvert untuk menampilkan true jika jenis yang akan dikonversi adalah salah satu yang dapat ditangani pengonversi. Misalnya, jika pengonversi untuk List pengonversi tersebut mungkin hanya menangani List, List, dan List.
  • Ganti metode CreateConverter untuk menampilkan instans kelas pengonversi yang akan menangani jenis yang akan dikonversi yang disediakan saat durasi.
  • Buat kelas pengonversi yang digunakan metode CreateConverter.

Pola pabrik diperlukan untuk generik terbuka karena kode untuk mengonversi objek ke dan dari string tidak sama untuk semua jenis. Pengonversi untuk jenis generik terbuka (List, misalnya) harus membuat pengonversi untuk jenis generik tertutup (List, misalnya) di belakang layar. Kode harus ditulis untuk menangani setiap jenis generik tertutup yang dapat ditangani pengonversi.

Jenis Enum mirip dengan jenis generik terbuka: pengonversi untuk Enum harus membuat pengonversi untuk Enum tertentu (WeekdaysEnum, misalnya) di belakang layar.

Penggunaan Utf8JsonReader dalam metode Read

Jika pengonversi Anda mengonversi objek JSON, Utf8JsonReader akan diposisikan pada token objek awal saat metode Read dimulai. Anda lalu harus membaca semua token dalam objek tersebut dan keluar dari metode dengan pembaca yang diposisikan pada token objek akhir yang sesuai. Jika Anda membaca di luar akhir objek, atau jika Anda berhenti sebelum mencapai token akhir yang sesuai, Anda mendapatkan pengecualian JsonException yang menunjukkan bahwa:

Pengonversi 'ConverterName' membaca terlalu banyak atau tidak cukup.

Misalnya, lihat pengonversi sampel pola pabrik sebelumnya. Metode Read dimulai dengan memastikan bahwa pembaca diposisikan pada token objek awal. Ini membaca sampai menemukan bahwa ini diposisikan pada token objek akhir berikutnya. Ini berhenti pada token objek akhir berikutnya karena tidak ada token objek mulai intervensi yang akan menunjukkan objek dalam objek. Aturan yang sama tentang token awal dan token akhir berlaku jika Anda mengonversi array. Misalnya, lihat sampel pengonversi Stack nanti dalam artikel ini.

Penanganan kesalahan

Pembuat serialisasi menyediakan penanganan khusus untuk jenis pengecualian JsonException dan NotSupportedException.

JsonException

Jika Anda menampilkan JsonException tanpa pesan, pembuat serialisasi membuat pesan yang menyertakan jalur ke bagian JSON yang menyebabkan kesalahan. Misalnya, pernyataan throw new JsonException() menghasilkan pesan kesalahan seperti contoh berikut:

Unhandled exception. System.Text.Json.JsonException:
The JSON value could not be converted to System.Object.
Path: $.Date | LineNumber: 1 | BytePositionInLine: 37.

Jika Anda memberikan pesan (misalnya, throw new JsonException("Error occurred")), pembuat serialisasi tetap mengatur properti Path, LineNumber, dan BytePositionInLine.

NotSupportedException

Jika Anda menampilkan NotSupportedException, Anda akan mendapatkan informasi jalur dalam pesan kapan saja. Jika Anda memberikan pesan, informasi jalur akan ditambahkan ke dalamnya. Misalnya, pernyataan throw new NotSupportedException("Error occurred.") menghasilkan pesan kesalahan seperti contoh berikut:

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

Kapan harus menampilkan jenis pengecualian

Jika payload JSON berisi token yang tidak valid untuk jenis yang dideserialisasi, tampilkan JsonException.

Jika Anda ingin melarang jenis tertentu, tampilkan NotSupportedException. Pengecualian inilah yang secara otomatis dilemparkan oleh pembuat serialisasi untuk jenis yang tidak didukung. Misalnya, System.Type tidak didukung karena alasan keamanan, jadi upaya untuk mendeserialisasinya akan menghasilkan NotSupportedException.

Anda dapat menampilkan pengecualian lain sesuai kebutuhan, tetapi tidak secara otomatis menyertakan informasi jalur JSON.

Mendaftarkan pengonversi kustom

Daftarkan pengonversi kustom agar metode Serialize dan Deserialize menggunakannya. Pilih salah satu pendekatan berikut:

  • Tambahkan instans kelas pengonversi ke kumpulan JsonSerializerOptions.Converters.
  • Terapkan atribut [JsonConverter] ke properti yang memerlukan pengonversi kustom.
  • Terapkan atribut [JsonConverter] ke kelas atau struktur yang mewakili jenis nilai kustom.

Sampel pendaftaran - Kumpulan pengonversi

Berikut ini contoh yang menjadikan DateTimeOffsetJsonConverter sebagai default untuk properti jenis DateTimeOffset:

var serializeOptions = new JsonSerializerOptions
{
    WriteIndented = true,
    Converters =
    {
        new DateTimeOffsetJsonConverter()
    }
};

jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);

Misalkan Anda melakukan serialisasi instans dari jenis berikut:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

Berikut ini contoh output JSON yang menunjukkan pengonversi kustom digunakan:

{
  "Date": "08/01/2019",
  "TemperatureCelsius": 25,
  "Summary": "Hot"
}

Kode berikut menggunakan pendekatan yang sama untuk mendeserialisasi menggunakan pengonversi kustom DateTimeOffset:

var deserializeOptions = new JsonSerializerOptions();
deserializeOptions.Converters.Add(new DateTimeOffsetJsonConverter());
weatherForecast = JsonSerializer.Deserialize(jsonString, deserializeOptions)!;

Sampel pendaftaran - [JsonConverter] di properti

Kode berikut memilih pengonversi kustom untuk properti Date:

public class WeatherForecastWithConverterAttribute
{
    [JsonConverter(typeof(DateTimeOffsetJsonConverter))]
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

Kode untuk serialisasi WeatherForecastWithConverterAttribute tidak memerlukan penggunaan JsonSerializeOptions.Converters:

var serializeOptions = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);

Kode untuk deserialisasi juga tidak memerlukan penggunaan Converters:

weatherForecast = JsonSerializer.Deserialize(jsonString)!;

Sampel pendaftaran - [JsonConverter] pada jenis

Berikut ini kode yang membuat struktur dan menerapkan atribut [JsonConverter] ke struktur tersebut:

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);
        }
    }
}

Berikut adalah pengonversi kustom untuk struktur sebelumnya:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace SystemTextJsonSamples
{
    public class TemperatureConverter : JsonConverter
    {
        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());
    }
}

Atribut [JsonConverter] pada struktur mendaftarkan pengonversi kustom sebagai default untuk properti jenis Temperature. Pengonversi secara otomatis digunakan pada properti TemperatureCelsius jenis berikut saat Anda menserialisasikan atau mendeserialisasikannya:

public class WeatherForecastWithTemperatureStruct
{
    public DateTimeOffset Date { get; set; }
    public Temperature TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

Prioritas pendaftaran pengonversi

Selama serialisasi atau deserialisasi, pengonversi dipilih untuk setiap elemen JSON dalam urutan berikut, tercantum dari prioritas tertinggi ke terendah:

  • [JsonConverter] diterapkan ke properti.
  • Pengonversi ditambahkan ke kumpulan Converters.
  • [JsonConverter] diterapkan ke jenis nilai kustom atau POCO.

Jika beberapa pengonversi kustom untuk jenis terdaftar dalam kumpulan Converters, pengonversi pertama yang menampilkan true untuk CanConvert akan digunakan.

Pengonversi bawaan hanya akan dipilih jika tidak ada pengonversi kustom yang berlaku yang terdaftar.

Sampel pengonversi untuk skenario umum

Bagian berikut menyediakan sampel pengonversi yang membahas beberapa skenario umum yang tidak ditangani oleh fungsionalitas bawaan.

  • Deserialisasi jenis yang disimpulkan ke properti objek.
  • Mendukung deserialisasi polimorfik.
  • Mendukung komunikasi dua arah untuk Stack.
  • Mendukung deserialisasi nilai string enum.
  • Menggunakan pengonversi sistem default.

  • Deserialisasi jenis yang disimpulkan ke properti objek.
  • Mendukung deserialisasi polimorfik.
  • Mendukung komunikasi dua arah untuk Stack.
  • Mendukung deserialisasi nilai string enum.

  • Deserialisasi jenis yang disimpulkan ke properti objek.
  • Mendukung Kamus dengan kunci non-string.
  • Mendukung deserialisasi polimorfik.
  • Mendukung komunikasi dua arah untuk Stack.

Untuk pengonversi sampel DataTable, lihat Jenis koleksi yang didukung.

Deserialisasi jenis yang disimpulkan ke properti objek

Saat deserialisasi ke properti jenis object, objek JsonElement akan dibuat. Alasannya adalah bahwa pembuat deserialisasi tidak tahu jenis CLR apa yang harus dibuat, dan tidak mencoba menebak. Misalnya, jika properti JSON memiliki "true", pembuat deserialisasi tidak menyimpulkan bahwa nilainya adalah Boolean, dan jika elemen memiliki "01/01/2019", pembuat deserialisasi tidak menyimpulkan bahwa itu adalah DateTime.

Inferensi jenis bisa tidak akurat. Jika pembuat deserialisasi mengurai angka JSON yang tidak memiliki titik desimal sebagai long, yang dapat mengakibatkan masalah di luar rentang jika nilai awalnya diserialisasikan sebagai ulong atau BigInteger. Mengurai angka yang memiliki titik desimal sebagai double mungkin kehilangan presisi jika angka awalnya diserialisasikan sebagai decimal.

Untuk skenario yang memerlukan inferensi jenis, kode berikut menunjukkan pengonversi kustom untuk properti object. Kode akan mengonversi:

  • true dan false ke Boolean
  • Angka tanpa desimal ke long
  • Angka dengan desimal ke double
  • Tanggal ke DateTime
  • String ke string
  • Segala sesuatu yang lain ke JsonElement

using System.Text.Json;
using System.Text.Json.Serialization;

namespace CustomConverterInferredTypesToObject
{
    public class ObjectToInferredTypesConverter : JsonConverter
    {
        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(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(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"
//}

Contoh menunjukkan kode pengonversi dan kelas WeatherForecast dengan properti object. Metode Main ini mendeserialisasi string JSON menjadi instans WeatherForecast, tanpa menggunakan pengonversi terlebih dahulu, lalu menggunakan pengonversi. Output konsol menunjukkan bahwa tanpa pengonversi jenis durasi untuk properti Date adalah JsonElement; dengan pengonversi, jenis durasi adalah DateTime.

Folder pengujian unit di namespace layanan System.Text.Json.Serialization memiliki lebih banyak contoh pengonversi kustom yang menangani deserialisasi ke properti object.

using System.Text.Json;
using System.Text.Json.Serialization;

namespace SystemTextJsonSamples
{
    public class ObjectToInferredTypesConverter
        : JsonConverter
    {
        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.");
    }
}

Kode berikut mendaftarkan pengonversi:

var deserializeOptions = new JsonSerializerOptions
{
    Converters =
    {
        new ObjectToInferredTypesConverter()
    }
};

Berikut ini contoh jenis dengan properti object:

public class WeatherForecastWithObjectProperties
{
    public object? Date { get; set; }
    public object? TemperatureCelsius { get; set; }
    public object? Summary { get; set; }
}

Contoh JSON berikut untuk deserialisasi berisi nilai yang akan dideserialisasi sebagai DateTime, long, dan string:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
}

Tanpa pengonversi kustom, deserialisasi menempatkan JsonElement di setiap properti.

Folder pengujian unit di namespace layanan System.Text.Json.Serialization memiliki lebih banyak contoh pengonversi kustom yang menangani deserialisasi ke properti object.

Mendukung Kamus dengan kunci non-string

Dukungan bawaan untuk kumpulan kamus adalah untuk Dictionary. Artinya, kunci harus berupa string. Untuk mendukung kamus dengan bilangan bulat atau jenis lain sebagai kunci, diperlukan pengonversi kustom.

Kode berikut menunjukkan pengonversi kustom yang berfungsi dengan Dictionary:

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 :
            JsonConverter> where TKey : struct, Enum
        {
            private readonly JsonConverter _valueConverter;
            private readonly Type _keyType;
            private readonly Type _valueType;

            public DictionaryEnumConverterInner(JsonSerializerOptions options)
            {
                // For performance, use the existing converter if available.
                _valueConverter = (JsonConverter)options
                    .GetConverter(typeof(TValue));

                // Cache the key and value types.
                _keyType = typeof(TKey);
                _valueType = typeof(TValue);
            }

            public override Dictionary Read(
                ref Utf8JsonReader reader,
                Type typeToConvert,
                JsonSerializerOptions options)
            {
                if (reader.TokenType != JsonTokenType.StartObject)
                {
                    throw new JsonException();
                }

                var dictionary = new Dictionary();

                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(ref reader, options)!;
                    }

                    // Add to dictionary.
                    dictionary.Add(key, value);
                }

                throw new JsonException();
            }

            public override void Write(
                Utf8JsonWriter writer,
                Dictionary 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();
            }
        }
    }
}

Kode berikut mendaftarkan pengonversi:

var serializeOptions = new JsonSerializerOptions();
serializeOptions.Converters.Add(new DictionaryTKeyEnumTValueConverter());

Pengonversi dapat menserialisasi dan mendeserialisasi properti TemperatureRanges kelas berikut yang menggunakan Enum:

public class WeatherForecastWithEnumDictionary
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
    public Dictionary? TemperatureRanges { get; set; }
}

public enum SummaryWordsEnum
{
    Cold, Hot
}

Output JSON dari serialisasi akan terlihat seperti contoh berikut:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "TemperatureRanges": {
    "Cold": 20,
    "Hot": 40
  }
}

Folder pengujian unit di namespace layanan System.Text.Json.Serialization memiliki lebih banyak contoh pengonversi kustom yang menangani kamus kunci non-string.

Mendukung deserialisasi polimorfik

Fitur bawaan menyediakan berbagai serialisasi polimorfik terbatas tetapi tidak ada dukungan untuk deserialisasi sama sekali. Deserialisasi memerlukan pengonversi kustom.

Misalkan, sebagai contoh, Anda memiliki kelas dasar abstrak Person, dengan kelas turunan Employee dan Customer. Deserialisasi polimorfik berarti bahwa pada waktu desain, Anda dapat menentukan Person sebagai target deserialisasi, dan objek Customer dan Employee di JSON dideserialisasi dengan benar pada durasi. Selama deserialisasi, Anda harus menemukan petunjuk yang mengidentifikasi jenis yang diperlukan di JSON. Jenis petunjuk yang tersedia bervariasi menurut setiap skenario. Misalnya, properti pembeda mungkin tersedia atau Anda mungkin harus bergantung pada ada atau tidak adanya properti tertentu. Rilis System.Text.Json saat ini tidak menyediakan atribut untuk menentukan cara menangani skenario deserialisasi polimorfik, sehingga diperlukan pengonversi kustom.

Kode berikut menunjukkan kelas dasar, dua kelas turunan, dan pengonversi kustom untuk mereka. Pengonversi menggunakan properti pembeda untuk melakukan deserialisasi polimorfik. Jenis pembeda tidak ada dalam definisi kelas tetapi dibuat selama serialisasi dan dibaca selama deserialisasi.

Penting

Kode contoh mengharuskan pasangan nama/nilai objek JSON untuk tetap berurutan, yang bukan persyaratan standar JSON.

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.Text.Json;
using System.Text.Json.Serialization;

namespace SystemTextJsonSamples
{
    public class PersonConverterWithTypeDiscriminator : JsonConverter
    {
        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();
        }
    }
}

Kode berikut mendaftarkan pengonversi:

var serializeOptions = new JsonSerializerOptions();
serializeOptions.Converters.Add(new PersonConverterWithTypeDiscriminator());

Pengonversi dapat mendeserialisasi JSON yang dibuat dengan menggunakan pengonversi yang sama untuk serialisasi, misalnya:

[
  {
    "TypeDiscriminator": 1,
    "CreditLimit": 10000,
    "Name": "John"
  },
  {
    "TypeDiscriminator": 2,
    "OfficeNumber": "555-1234",
    "Name": "Nancy"
  }
]

Kode pengonversi dalam contoh sebelumnya membaca dan menulis setiap properti secara manual. Alternatifnya adalah memanggil Deserialize atau Serialize untuk melakukan beberapa pekerjaan. Misalnya, lihat posting StackOverflow ini.

Cara alternatif untuk melakukan deserialisasi polimorfik

Anda dapat memanggil Deserialize dalam metode Read:

  • Buat klon instans Utf8JsonReader. Karena Utf8JsonReader adalah struktur, ini hanya memerlukan pernyataan penetapan.
  • Gunakan klon untuk membaca token pembeda.
  • Panggil Deserialize menggunakan instans Reader asli setelah Anda mengetahui jenis yang Anda butuhkan. Anda dapat memanggil Deserialize karena instans Reader asli tetap diposisikan untuk membaca token objek awal.

Kerugian dari metode ini adalah Anda tidak dapat meneruskan instans opsi asli yang mendaftarkan pengonversi ke Deserialize. Melakukannya akan menyebabkan luapan tumpukan, seperti yang dijelaskan dalam Properti yang diperlukan. Contoh berikut menunjukkan metode Read yang menggunakan alternatif ini:

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(ref reader)!,
        TypeDiscriminator.Employee => JsonSerializer.Deserialize(ref reader)!,
        _ => throw new JsonException()
    };
    return person;
}

Mendukung perjalanan pulang pergi untuk Stack

Jika Anda mendeserialisasi string JSON menjadi objek Stack dan kemudian membuat serialisasi objek tersebut, konten tumpukan dalam urutan terbalik. Perilaku ini berlaku untuk jenis dan antarmuka berikut, dan jenis yang ditentukan pengguna yang berasal dari mereka:

  • Stack
  • Stack
  • ConcurrentStack
  • ImmutableStack
  • IImmutableStack

Untuk mendukung serialisasi dan deserialisasi yang mempertahankan urutan asli dalam tumpukan, diperlukan pengonversi kustom.

Kode berikut menunjukkan pengonversi kustom yang memungkinkan komunikasi dua arah ke dan dari Stack objek:

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 : JsonConverter>
    {
        public override Stack Read(
            ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.StartArray)
            {
                throw new JsonException();
            }
            reader.Read();

            var elements = new Stack();

            while (reader.TokenType != JsonTokenType.EndArray)
            {
                elements.Push(JsonSerializer.Deserialize(ref reader, options)!);

                reader.Read();
            }

            return elements;
        }

        public override void Write(
            Utf8JsonWriter writer, Stack value, JsonSerializerOptions options)
        {
            writer.WriteStartArray();

            var reversed = new Stack(value);

            foreach (T item in reversed)
            {
                JsonSerializer.Serialize(writer, item, options);
            }

            writer.WriteEndArray();
        }
    }
}

Kode berikut mendaftarkan pengonversi:

var options = new JsonSerializerOptions
{
    Converters = { new JsonConverterFactoryForStackOfT() },
};

Mendukung deserialisasi nilai string enum

Secara default, JsonStringEnumConverter bawaan dapat menserialisasi dan mendeserialisasi nilai string untuk enum. Ini berfungsi tanpa kebijakan penamaan tertentu atau dengan kebijakan penamaan CamelCase. Itu tidak mendukung kebijakan penamaan lainnya, seperti snake case. Untuk informasi tentang kode pengonversi kustom yang dapat mendukung komunikasi dua arah ke dan dari nilai string enum saat menggunakan kebijakan penamaan snake case, lihat masalah GitHub dotnet/runtime #31619.

Menggunakan pengonversi sistem default

Dalam beberapa skenario, Anda mungkin ingin menggunakan pengonversi sistem default dalam pengonversi kustom. Untuk melakukannya, dapatkan pengonversi sistem dari properti JsonSerializerOptions.Default, seperti yang ditunjukkan dalam contoh berikut:

public class MyCustomConverter : JsonConverter
{
    private readonly static JsonConverter s_defaultConverter = 
        (JsonConverter)JsonSerializerOptions.Default.GetConverter(typeof(int));

    // Custom serialization logic
    public override void Write(
        Utf8JsonWriter writer, int value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }

    // Fall back to default deserialization logic
    public override int Read(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return s_defaultConverter.Read(ref reader, typeToConvert, options);
    }
}

Menangani nilai null

Secara default, pembuat serialisasi menangani nilai null sebagai berikut:

  • Untuk jenis referensi dan jenis Nullable:

    • Ini tidak meneruskan null ke pengonversi kustom pada serialisasi.
    • Ini tidak meneruskan JsonTokenType.Null ke pengonversi kustom saat deserialisasi.
    • Ini akan menampilkan instans null saat deserialisasi.
    • Ini akan menulis null langsung dengan penulis saat serialisasi.
  • Untuk jenis nilai yang tidak dapat diubah ke null:

    • Ini meneruskan JsonTokenType.Null ke pengonversi kustom saat deserialisasi. (Jika tidak ada pengonversi kustom yang tersedia, pengecualian JsonException akan ditampilkan oleh pengonversi internal untuk jenis tersebut.)

Perilaku penanganan null ini terutama untuk mengoptimalkan performa dengan melewatkan panggilan tambahan ke pengonversi. Selain itu, ini menghindari memaksa pengonversi untuk jenis yang dapat diubah ke null untuk diperiksa untuk null di awal setiap penggantian metode Read dan Write.

Untuk mengaktifkan pengonversi kustom untuk menangani null untuk jenis nilai atau referensi, ganti JsonConverter.HandleNull untuk menampilkan true, seperti yang ditunjukkan dalam contoh berikut:

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
    {
        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(json)!;
            Console.WriteLine($"Description: {point.Description}");
        }
    }
}

// Produces output like the following example:
//
//Description: No description provided.

Mempertahankan referensi

Secara default, data referensi hanya di-cache untuk setiap panggilan ke Serialize atau Deserialize. Untuk mempertahankan referensi dari satu panggilan Serialize/Deserialize ke panggilan lain, akar instans ReferenceResolver di situs panggilan Serialize/Deserialize. Kode berikut menunjukkan contoh untuk skenario ini:

  • Anda menulis pengonversi kustom untuk jenis Company.
  • Anda tidak ingin menserialisasi properti Supervisor secara manual, yang merupakan Employee. Anda ingin mendelegasikannya ke pembuat serialisasi dan Anda juga ingin menyimpan referensi yang telah Anda simpan.

Berikut ini kelas Employee dan Company:

public class Employee
{
    public string? Name { get; set; }
    public Employee? Manager { get; set; }
    public List? DirectReports { get; set; }
    public Company? Company { get; set; }
}

public class Company
{
    public string? Name { get; set; }
    public Employee? Supervisor { get; set; }
}

Pengonversi akan terlihat seperti ini:

class CompanyConverter : JsonConverter
{
    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();
    }
}

Kelas yang berasal dari ReferenceResolver menyimpan referensi dalam kamus:

class MyReferenceResolver : ReferenceResolver
{
    private uint _referenceCount;
    private readonly Dictionary _referenceIdToObjectMap = new ();
    private readonly Dictionary _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;
    }
}

Kelas yang berasal dari ReferenceHandler menyimpan instans MyReferenceResolver dan membuat instans baru hanya jika diperlukan (dalam metode bernama Reset dalam contoh ini):

class MyReferenceHandler : ReferenceHandler
{
    public MyReferenceHandler() => Reset();

    private ReferenceResolver? _rootedResolver;
    public override ReferenceResolver CreateResolver() => _rootedResolver!;
    public void Reset() => _rootedResolver = new MyReferenceResolver();

}

Saat kode sampel memanggil pembuat serialisasi, kode tersebut menggunakan instans JsonSerializerOptions di mana properti ReferenceHandler diatur ke instans MyReferenceHandler. Jika Anda mengikuti pola ini, pastikan untuk mengatur ulang kamus ReferenceResolver saat Anda selesai melakukan serialisasi, agar tidak terus berkembang.

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();

Contoh sebelumnya hanya melakukan serialisasi, tetapi pendekatan serupa dapat diadopsi untuk deserialisasi.

Sampel pengonversi kustom lainnya

Artikel Migrasi dari Newtonsoft.Json ke System.Text.Json berisi sampel tambahan pengonversi kustom.

Folder pengujian unit dalam kode sumber System.Text.Json.Serialization menyertakan sampel pengonversi kustom lain, seperti:

  • Pengonversi Int32 yang mengonversi null menjadi 0 saat deserialisasi
  • Pengonversi Int32 yang memungkinkan nilai angka dan string saat deserialisasi
  • Pengonversi Enum
  • Pengonversi List yang menerima data eksternal
  • Pengonversi panjang[] yang berfungsi dengan daftar angka yang dibatasi koma

Jika Anda perlu membuat pengonversi yang mengubah perilaku pengonversi bawaan yang ada, Anda bisa mendapatkan kode sumber pengonversi yang ada untuk berfungsi sebagai titik awal penyesuaian.

Sumber Daya Tambahan:

  • Kode sumber untuk pengonversi bawaan
  • System.Text.Json ringkasan
  • Cara menserialisasi dan mendeserialisasi JSON
  • Membuat instans JsonSerializerOptions
  • Mengaktifkan pencocokan yang tidak peka huruf besar/kecil
  • Menyesuaikan nama dan nilai properti
  • Mengabaikan properti
  • Mengizinkan JSON yang tidak valid
  • Menangani JSON yang meluap atau menggunakan JsonElement atau JsonNode
  • Mempertahankan referensi dan menangani referensi melingkar
  • Mendeserialisasi ke jenis yang tidak dapat diubah dan pengakses non-publik
  • Serialisasi polimorfik
  • Migrasi dari Newtonsoft.Json ke System.Text.Json
  • Menyesuaikan pengodean karakter
  • Menggunakan DOM, Utf8JsonReader, dan Utf8JsonWriter
  • Dukungan DateTime dan DateTimeOffset
  • Cara menggunakan pembuatan sumber
  • Jenis kumpulan yang didukung
  • System.Text.Json Referensi API
  • System.Text.Json.Referensi API serialisasi