最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

.NET中自定義JSON轉(zhuǎn)換器的實(shí)戰(zhàn)指南

 更新時(shí)間:2025年08月05日 08:46:39   作者:墨夶  
在.NET開發(fā)中,JSON序列化與反序列化是日常開發(fā)的核心操作,然而,標(biāo)準(zhǔn)的序列化器(如System.Text.Json)并不能滿足所有場景需求,自定義JSON轉(zhuǎn)換器正是解決這些問題的利器,本文將通過基本模式和工廠模式的實(shí)戰(zhàn)案例,帶你掌握自定義轉(zhuǎn)換器的核心技巧,需要的朋友可以參考下

一、為什么需要自定義 JSON 轉(zhuǎn)換器?

在 .NET 開發(fā)中,JSON 序列化與反序列化是日常開發(fā)的核心操作。然而,標(biāo)準(zhǔn)的序列化器(如 System.Text.Json)并不能滿足所有場景需求。以下是常見的痛點(diǎn):

  1. 數(shù)據(jù)格式不兼容
    • 例如:前端要求日期格式為 "yyyy-MM-dd",而默認(rèn)格式為 ISO 8601。
  2. 復(fù)雜類型處理
    • 例如:枚舉類型需要自定義映射規(guī)則(如 Enum 轉(zhuǎn) string 而非 int)。
  3. 性能瓶頸
    • 例如:需要避免頻繁創(chuàng)建臨時(shí)對象或優(yōu)化內(nèi)存分配。
  4. 特殊業(yè)務(wù)邏輯
    • 例如:將數(shù)據(jù)庫中的科學(xué)計(jì)數(shù)法字段(1.23E+08)轉(zhuǎn)為正常數(shù)字格式。

自定義 JSON 轉(zhuǎn)換器JsonConverter<T>)正是解決這些問題的利器。本文將通過 基本模式工廠模式 的實(shí)戰(zhàn)案例,帶你掌握自定義轉(zhuǎn)換器的核心技巧。

二、基本模式:實(shí)現(xiàn) JsonConverter<T>

2.1 適用場景

  • 非泛型類型封閉式泛型類型(如 List<DateTime>Dictionary<string, int>)。
  • 需要控制特定類型的序列化/反序列化邏輯。

2.2 核心方法

  • Read:將 JSON 反序列化為 .NET 對象。
  • Write:將 .NET 對象序列化為 JSON。
  • CanConvert(可選):判斷是否支持該類型。

2.3 實(shí)戰(zhàn)案例:日期格式自定義轉(zhuǎn)換器

場景需求

  • 目標(biāo):將 DateTime 字段從默認(rèn)的 ISO 8601 格式("2025-07-19T17:11:39Z")轉(zhuǎn)為 "yyyy-MM-dd" 格式。
  • 代碼實(shí)現(xiàn)
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

// 自定義 DateTime 轉(zhuǎn)換器
public class CustomDateTimeConverter : JsonConverter<DateTime>
{
    private const string DateFormat = "yyyy-MM-dd";

    // 反序列化:JSON -> DateTime
    public override DateTime Read(
        ref Utf8JsonReader reader, 
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        // 處理 null 值
        if (reader.TokenType == JsonTokenType.Null)
            return default;

        // 讀取 JSON 字符串
        var dateString = reader.GetString();
        if (DateTime.TryParseExact(dateString, DateFormat, null, System.Globalization.DateTimeStyles.None, out var result))
        {
            return result;
        }

        throw new JsonException($"Invalid date format. Expected '{DateFormat}' but got '{dateString}'");
    }

    // 序列化:DateTime -> JSON
    public override void Write(
        Utf8JsonWriter writer, 
        DateTime value, 
        JsonSerializerOptions options)
    {
        // 格式化為指定格式
        writer.WriteStringValue(value.ToString(DateFormat));
    }
}

使用示例

public class Person
{
    public string Name { get; set; }
    [JsonConverter(typeof(CustomDateTimeConverter))] // 綁定轉(zhuǎn)換器
    public DateTime Birthday { get; set; }
}

// 測試代碼
var person = new Person 
{ 
    Name = "Alice", 
    Birthday = new DateTime(2025, 7, 19) 
};

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    Converters = { new CustomDateTimeConverter() } // 注冊全局轉(zhuǎn)換器
};

string json = JsonSerializer.Serialize(person, options);
Console.WriteLine(json); 
// 輸出: {"Name":"Alice","Birthday":"2025-07-19"}

技術(shù)細(xì)節(jié)

  • Utf8JsonReader:高性能的 JSON 解析器,直接操作 UTF-8 緩沖區(qū),避免字符串轉(zhuǎn)換開銷。
  • Utf8JsonWriter:直接生成 UTF-8 字節(jié)流,減少中間字符串分配。
  • 異常處理JsonException 是序列化框架的標(biāo)準(zhǔn)異常類型。

三、工廠模式:處理開放式泛型類型

3.1 適用場景

  • 開放式泛型類型(如 List<T>、Dictionary<TKey, TValue>)。
  • 多態(tài)類型(如 Enum 或動(dòng)態(tài)類型)。

3.2 核心方法

  • CanConvert:判斷是否支持當(dāng)前類型。
  • CreateConverter:動(dòng)態(tài)創(chuàng)建特定類型的轉(zhuǎn)換器實(shí)例。

3.3 實(shí)戰(zhàn)案例:泛型集合轉(zhuǎn)換器

場景需求

  • 目標(biāo):支持任意 List<T> 類型的序列化,其中 T 可能是 int、string 或自定義類型。

代碼實(shí)現(xiàn)

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

// 工廠類:處理 List<T>
public class ListConverterFactory : JsonConverterFactory
{
    // 判斷是否支持當(dāng)前類型
    public override bool CanConvert(Type typeToConvert)
    {
        // 僅支持 List<T> 類型
        return typeToConvert.IsGenericType && 
               typeToConvert.GetGenericTypeDefinition() == typeof(List<>);
    }

    // 動(dòng)態(tài)創(chuàng)建轉(zhuǎn)換器
    public override JsonConverter CreateConverter(
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        // 獲取 T 的類型
        var genericType = typeToConvert.GetGenericArguments()[0];
        // 創(chuàng)建泛型轉(zhuǎn)換器實(shí)例
        return (JsonConverter)Activator.CreateInstance(
            typeof(ListConverter<>).MakeGenericType(genericType));
    }
}

// 泛型轉(zhuǎn)換器:處理 List<T>
public class ListConverter<T> : JsonConverter<List<T>>
{
    // 反序列化:JSON -> List<T>
    public override List<T> Read(
        ref Utf8JsonReader reader, 
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartArray)
            throw new JsonException("Expected start of array");

        var list = new List<T>();
        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndArray)
                break;

            var item = JsonSerializer.Deserialize<T>(ref reader, options);
            list.Add(item);
        }

        return list;
    }

    // 序列化:List<T> -> JSON
    public override void Write(
        Utf8JsonWriter writer, 
        List<T> value, 
        JsonSerializerOptions options)
    {
        writer.WriteStartArray();
        foreach (var item in value)
        {
            JsonSerializer.Serialize(writer, item, options);
        }
        writer.WriteEndArray();
    }
}

使用示例

public class Product
{
    public string Name { get; set; }
    public List<int> Ratings { get; set; }
}

// 注冊工廠轉(zhuǎn)換器
var options = new JsonSerializerOptions
{
    WriteIndented = true,
    Converters = { new ListConverterFactory() }
};

var product = new Product
{
    Name = "Laptop",
    Ratings = new List<int> { 5, 4, 5 }
};

string json = JsonSerializer.Serialize(product, options);
Console.WriteLine(json);
// 輸出: {"Name":"Laptop","Ratings":[5,4,5]}

技術(shù)細(xì)節(jié)

  • 泛型反射:通過 MakeGenericType 動(dòng)態(tài)創(chuàng)建泛型轉(zhuǎn)換器。
  • 遞歸序列化JsonSerializer.Deserialize<T>() 自動(dòng)處理嵌套類型。

四、性能優(yōu)化技巧

4.1 避免頻繁創(chuàng)建對象

  • 復(fù)用 JsonSerializerOptions:全局配置并復(fù)用,避免重復(fù)解析設(shè)置。
  • 緩存 JsonConverter 實(shí)例:在工廠模式中緩存已創(chuàng)建的轉(zhuǎn)換器。

4.2 使用高性能 API

  • Utf8JsonReader / Utf8JsonWriter:比 JsonTextReader 快 30%+,且內(nèi)存占用更低。
  • Span 支持:避免不必要的字符串分配。

4.3 內(nèi)存優(yōu)化

  • 異步處理:對于大型數(shù)據(jù),使用 JsonSerializer.DeserializeAsync。
  • 流式處理:結(jié)合 Stream 逐塊讀寫,避免一次性加載大文件。

五、高級場景:科學(xué)計(jì)數(shù)法轉(zhuǎn)字符串

5.1 問題描述

數(shù)據(jù)庫中的 decimal(18,2) 字段在 JSON 中可能被序列化為科學(xué)計(jì)數(shù)法:

{ "Price": "1.23E+08" }

而前端期望的是:

{ "Price": 123000000 }

5.2 解決方案

public class DecimalConverter : JsonConverter<decimal>
{
    public override decimal Read(
        ref Utf8JsonReader reader, 
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        // 解析 JSON 字符串為 decimal
        return decimal.Parse(reader.GetString()!);
    }

    public override void Write(
        Utf8JsonWriter writer, 
        decimal value, 
        JsonSerializerOptions options)
    {
        // 將 decimal 轉(zhuǎn)為固定格式的字符串
        writer.WriteStringValue(value.ToString("F2"));
    }
}

綁定模型

public class Product
{
    [JsonConverter(typeof(DecimalConverter))]
    public decimal Price { get; set; }
}

六、常見陷阱與解決方案

6.1 CanConvert 方法誤判

  • 問題:未正確覆蓋 CanConvert,導(dǎo)致轉(zhuǎn)換器無法匹配目標(biāo)類型。
  • 解決方案:在工廠模式中,嚴(yán)格判斷類型是否符合預(yù)期。

6.2 嵌套類型處理失敗

  • 問題:轉(zhuǎn)換器未處理嵌套對象(如 Dictionary<string, List<int>>)。
  • 解決方案:遞歸調(diào)用 JsonSerializer,或手動(dòng)拆解結(jié)構(gòu)。

6.3 線程安全問題

  • 問題:共享的 JsonSerializerOptions 被多個(gè)線程修改。
  • 解決方案:使用 ThreadLocal<JsonSerializerOptions> 或每次創(chuàng)建新實(shí)例。

七、自定義轉(zhuǎn)換器的設(shè)計(jì)哲學(xué)

模式適用類型核心方法典型場景
基本模式非泛型/封閉式泛型Read / Write日期格式化、枚舉映射
工廠模式開放式泛型/多態(tài)CanConvert / CreateConverter泛型集合、動(dòng)態(tài)類型

設(shè)計(jì)原則

  1. 最小化依賴:避免在轉(zhuǎn)換器中引入復(fù)雜邏輯。
  2. 高內(nèi)聚低耦合:每個(gè)轉(zhuǎn)換器只處理一種類型或模式。
  3. 性能優(yōu)先:優(yōu)先使用 Utf8JsonReaderUtf8JsonWriter
  4. 可測試性:通過單元測試驗(yàn)證轉(zhuǎn)換器的正確性。

代碼模板

基本模式模板

public class CustomConverter<T> : JsonConverter<T>
{
    public override T Read(
        ref Utf8JsonReader reader, 
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        // 實(shí)現(xiàn)反序列化邏輯
    }

    public override void Write(
        Utf8JsonWriter writer, 
        T value, 
        JsonSerializerOptions options)
    {
        // 實(shí)現(xiàn)序列化邏輯
    }
}

工廠模式模板

public class CustomConverterFactory : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        // 判斷是否支持類型
    }

    public override JsonConverter CreateConverter(
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        // 動(dòng)態(tài)創(chuàng)建轉(zhuǎn)換器
    }
}

以上就是.NET中自定義JSON轉(zhuǎn)換器的實(shí)戰(zhàn)指南的詳細(xì)內(nèi)容,更多關(guān)于.NET自定義JSON轉(zhuǎn)換器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • WinForm中實(shí)現(xiàn)picturebox自適應(yīng)圖片大小的方法

    WinForm中實(shí)現(xiàn)picturebox自適應(yīng)圖片大小的方法

    這篇文章主要介紹了WinForm中實(shí)現(xiàn)picturebox自適應(yīng)圖片大小的方法,涉及pictureBox控件相關(guān)屬性設(shè)置技巧,需要的朋友可以參考下
    2017-05-05
  • C# datatable 不能通過已刪除的行訪問該行的信息處理方法

    C# datatable 不能通過已刪除的行訪問該行的信息處理方法

    采用datatable.Rows[i].Delete()刪除行后再訪問該表時(shí)出現(xiàn)出現(xiàn)“不能通過已刪除的行訪問該行的信息”的錯(cuò)誤
    2012-11-11
  • unity scrollRect實(shí)現(xiàn)按頁碼翻頁效果

    unity scrollRect實(shí)現(xiàn)按頁碼翻頁效果

    這篇文章主要為大家詳細(xì)介紹了unity scrollRect實(shí)現(xiàn)按頁碼翻頁效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • DevExpress實(shí)現(xiàn)自定義TreeListNode的Tooltip的方法

    DevExpress實(shí)現(xiàn)自定義TreeListNode的Tooltip的方法

    這篇文章主要介紹了DevExpress實(shí)現(xiàn)自定義TreeListNode的Tooltip的方法,需要的朋友可以參考下
    2014-08-08
  • C# GetField方法的應(yīng)用實(shí)例講解

    C# GetField方法的應(yīng)用實(shí)例講解

    C#中的GetField是一個(gè)反射方法,用于獲取指定類型的字段信息,它可以通過字段名稱來獲取字段對象,并且可以在運(yùn)行時(shí)動(dòng)態(tài)地訪問和操作這些字段,本文給大家介紹了C# GetField方法的應(yīng)用,需要的朋友可以參考下
    2024-04-04
  • 利用C#快速查出哪些QQ好友空間屏蔽了自己

    利用C#快速查出哪些QQ好友空間屏蔽了自己

    我們經(jīng)常會(huì)遇到以下情況吧:想點(diǎn)擊好友空間看看他最近的動(dòng)態(tài),結(jié)果發(fā)現(xiàn)自己需要申請權(quán)限!別擔(dān)心,本文將為大家介紹如何利用C#快速查出哪些QQ好友空間屏蔽了自己,需要的可以參考一下
    2022-02-02
  • C# 枚舉的使用簡介

    C# 枚舉的使用簡介

    這篇文章主要介紹了C# 枚舉的簡單使用,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • WinForm解決窗體大量控件加載閃爍卡頓的問題

    WinForm解決窗體大量控件加載閃爍卡頓的問題

    在使用 WinForm 桌面應(yīng)用程序時(shí),當(dāng)窗體中包含大量控件(如按鈕、標(biāo)簽、文本框等)或進(jìn)行頻繁界面更新時(shí),常常會(huì)出現(xiàn)界面閃爍、加載卡頓、重繪不完整等問題,本文將介紹一種高效且廣泛驗(yàn)證的解決方案,需要的朋友可以參考下
    2025-08-08
  • C#對NULL的簡化賦值的方法總結(jié)

    C#對NULL的簡化賦值的方法總結(jié)

    在C#中,對null賦值意味著將引用類型的變量設(shè)置為無引用或者說空引用,當(dāng)你聲明一個(gè)引用類型的變量,如果沒有給它初始化具體的對象,那么它的值就是null,本文給大家介紹了C#對NULL的簡化賦值的方法總結(jié),需要的朋友可以參考下
    2024-11-11
  • C#實(shí)現(xiàn)漢字轉(zhuǎn)區(qū)位碼的示例代碼

    C#實(shí)現(xiàn)漢字轉(zhuǎn)區(qū)位碼的示例代碼

    區(qū)位碼是一個(gè)4位的十進(jìn)制數(shù),每個(gè)區(qū)位碼都對應(yīng)著一個(gè)唯一的漢字,區(qū)位碼的前兩位叫做區(qū)碼,后兩位叫做位碼,下面我們就來看看如何使用C#實(shí)現(xiàn)漢字轉(zhuǎn)區(qū)位碼吧
    2024-01-01

最新評論

迁西县| 黄山市| 北流市| 渝北区| 高安市| 香港| 潮州市| 河曲县| 高邮市| 博湖县| 体育| 房山区| 石楼县| 祁连县| 谢通门县| 陕西省| 嘉峪关市| 理塘县| 喜德县| 阳江市| 海伦市| 和田县| 会昌县| 乳源| 开封市| 札达县| 江都市| 特克斯县| 从江县| 乐陵市| 白河县| 万载县| 黔江区| 科技| 靖宇县| 凤凰县| 广南县| 麦盖提县| 金山区| 玉山县| 青州市|