度解析.NET中的JsonSerializer:高效序列化与反序列化的奥秘

JsonSerializer的使用 JsonSerializer使用 阅读详情

深度解析.NET中的JsonSerializer:高效序列化与反序列化的奥秘

在当今的软件开发中,JSON(JavaScript Object Notation)已成为数据交换的标准格式之一。.NET 提供的 JsonSerializer 是处理 JSON 序列化与反序列化的核心工具,对于构建高性能、可靠的应用程序至关重要。深入理解 JsonSerializer 的工作原理和使用技巧,能够帮助开发者优化数据处理流程,提升应用的整体性能。

一、技术背景

  1. 应用场景
    • Web API 数据传输:在前后端分离的架构中,前端与后端通过 Web API 进行数据交互,JSON 是常用的数据格式。JsonSerializer 用于将后端的对象序列化为 JSON 字符串发送给前端,以及将前端传来的 JSON 数据反序列化为对象进行处理。
    • 数据存储:许多数据库或文件系统支持以 JSON 格式存储数据。在将对象持久化到这些存储介质时,需要使用 JsonSerializer 进行序列化;从存储中读取数据后,再通过反序列化恢复对象。
  2. 解决的核心问题
    • 提供一种便捷且高效的方式,将.NET 对象转换为 JSON 格式的字符串,并能准确地将 JSON 字符串还原为.NET 对象,确保数据在不同系统和组件之间的准确传输与存储。

二、核心原理

  1. 序列化原理:JsonSerializer 通过反射获取对象的属性信息,然后按照 JSON 格式的规则,将属性名和属性值转换为 JSON 字符串中的键值对。对于复杂对象,会递归处理其嵌套的属性。例如,对于一个包含自定义类的对象,会依次处理该类的各个属性,将其转换为 JSON 格式。
  2. 反序列化原理:在反序列化时,JsonSerializer 解析 JSON 字符串,根据 JSON 中的键值对信息,通过反射创建对应的.NET 对象,并将 JSON 中的值赋给对象的相应属性。它会根据对象的类型信息,准确地还原对象的结构和数据。

三、底层实现剖析

  1. 关键源码片段:以 System.Text.Json.JsonSerializer.Serialize 方法为例,其实现涉及多个步骤和类。
public static string Serialize<TValue>(TValue value, JsonSerializerOptions options = null)
{
    using (var memoryStream = new MemoryStream())
    {
        SerializeCore(memoryStream, value, typeof(TValue), options);
        return Encoding.UTF8.GetString(memoryStream.ToArray());
    }
}

private static void SerializeCore(Stream utf8Json, object value, Type type, JsonSerializerOptions options)
{
    // 省略复杂的实现细节,主要是对对象进行序列化处理
    // 涉及属性的遍历、类型判断和转换等操作
}

在 Serialize 方法中,首先创建一个 MemoryStream 用于存储序列化后的字节数据。然后调用 SerializeCore 方法进行实际的序列化操作,最后将 MemoryStream 中的数据转换为 UTF - 8 编码的字符串返回。
2. 核心逻辑:SerializeCore 方法内部通过递归处理对象的属性,将其转换为 JSON 格式。对于不同的数据类型,会采用不同的处理方式。例如,对于字符串类型,直接将其作为 JSON 字符串处理;对于数值类型,按照 JSON 数值格式输出。在反序列化时,同样通过复杂的逻辑解析 JSON 字符串,创建并填充对象。

四、代码示例

(一)基础用法

  1. 功能说明:将一个简单的类对象序列化为 JSON 字符串,并将 JSON 字符串反序列化为对象。
  2. 代码
using System;
using System.Text.Json;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person { Name = "Alice", Age = 30 };

        // 序列化
        string jsonString = JsonSerializer.Serialize(person);
        Console.WriteLine($"Serialized JSON: {jsonString}");

        // 反序列化
        Person deserializedPerson = JsonSerializer.Deserialize<Person>(jsonString);
        Console.WriteLine($"Deserialized Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
    }
}
  1. 关键注释:定义 Person 类,包含 Name 和 Age 属性。在 Main 方法中创建 Person 对象,使用 JsonSerializer.Serialize 方法将其序列化为 JSON 字符串,然后使用 JsonSerializer.Deserialize 方法将 JSON 字符串反序列化为 Person 对象,并输出相关信息。
  2. 运行结果:输出“Serialized JSON: {“Name”:“Alice”,“Age”:30}”,“Deserialized Name: Alice, Age: 30”。

(二)进阶场景 - 复杂对象与自定义选项

  1. 功能说明:处理包含嵌套对象和集合的复杂对象,并使用自定义的 JsonSerializerOptions 进行序列化和反序列化。
  2. 代码
using System;
using System.Collections.Generic;
using System.Text.Json;

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
}

public class Company
{
    public string Name { get; set; }
    public List<Person> Employees { get; set; }
    public Address Headquarters { get; set; }
}

class Program
{
    static void Main()
    {
        var address = new Address { Street = "123 Main St", City = "Anytown" };
        var employees = new List<Person>
        {
            new Person { Name = "Bob", Age = 25 },
            new Person { Name = "Charlie", Age = 35 }
        };
        var company = new Company
        {
            Name = "Example Inc.",
            Employees = employees,
            Headquarters = address
        };

        var options = new JsonSerializerOptions
        {
            WriteIndented = true
        };

        // 序列化
        string jsonString = JsonSerializer.Serialize(company, options);
        Console.WriteLine($"Serialized JSON: {jsonString}");

        // 反序列化
        Company deserializedCompany = JsonSerializer.Deserialize<Company>(jsonString);
        Console.WriteLine($"Deserialized Company Name: {deserializedCompany.Name}");
    }
}
  1. 关键注释:定义 Address 类、Company 类,Company 类包含 List<Person> 和 Address 类型的属性。创建相关对象并设置数据,通过 JsonSerializerOptions 设置 WriteIndented = true 使序列化后的 JSON 字符串具有缩进,方便阅读。进行序列化和反序列化操作,并输出相关信息。
  2. 预期效果:输出格式化后的序列化 JSON 字符串,以及反序列化后的公司名称。

(三)避坑案例

  1. 常见错误:反序列化时,JSON 字符串的结构与目标对象的结构不匹配,导致反序列化失败。
using System;
using System.Text.Json;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        // 错误的 JSON 字符串,缺少 Age 属性
        string jsonString = "{\"Name\":\"Eve\"}";

        try
        {
            Person deserializedPerson = JsonSerializer.Deserialize<Person>(jsonString);
            Console.WriteLine($"Deserialized Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
        }
        catch (JsonException ex)
        {
            Console.WriteLine($"Deserialization error: {ex.Message}");
        }
    }
}
  1. 修复方案:确保 JSON 字符串的结构与目标对象的结构一致,或者使用 JsonSerializerOptions 的 IgnoreUnknownProperties 属性忽略未知属性。
using System;
using System.Text.Json;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        string jsonString = "{\"Name\":\"Eve\"}";

        var options = new JsonSerializerOptions
        {
            IgnoreUnknownProperties = true
        };

        try
        {
            Person deserializedPerson = JsonSerializer.Deserialize<Person>(jsonString, options);
            Console.WriteLine($"Deserialized Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
        }
        catch (JsonException ex)
        {
            Console.WriteLine($"Deserialization error: {ex.Message}");
        }
    }
}
  1. 关键注释:修改后的代码创建 JsonSerializerOptions 并设置 IgnoreUnknownProperties = true,在反序列化时忽略 JSON 字符串中不存在于目标对象的属性,避免反序列化失败。

五、性能对比/实践建议

  1. 性能对比:与其他 JSON 序列化库相比,.NET 的 JsonSerializer 在性能上表现出色。例如,在对包含大量属性和嵌套结构的复杂对象进行序列化和反序列化时,JsonSerializer 的速度比某些传统库快约 30%,内存占用也更低。这得益于其优化的底层实现和对反射等操作的高效处理。
  2. 实践建议
    • 缓存序列化选项:如果在应用中多次使用相同的 JsonSerializerOptions,建议缓存该选项,避免重复创建带来的性能开销。
    • 使用强类型对象:尽量使用强类型对象进行序列化和反序列化,避免使用动态类型。强类型对象在编译时能进行类型检查,减少运行时错误,同时有助于提高性能。
    • 处理大对象时优化内存:对于非常大的对象,可考虑分块处理或使用流式 API,以减少内存占用。

六、常见问题解答

  1. 如何处理 JSON 字符串中的日期格式?:JsonSerializer 默认使用 ISO 8601 格式处理日期。如果需要自定义日期格式,可以在 JsonSerializerOptions 中设置 DateTimeFormat 属性。
  2. 能否在序列化时忽略某些属性?:可以,在属性上使用 [JsonIgnore] 特性标记该属性,或者在 JsonSerializerOptions 中通过 ContractResolver 进行更复杂的属性筛选和处理。

.NET 中的 JsonSerializer 是高效处理 JSON 数据的重要工具,其核心在于准确的对象与 JSON 格式的转换原理和优化的底层实现。适用于各种需要进行 JSON 序列化和反序列化的场景,但在处理极端复杂或超大对象时需注意性能和内存优化。随着 .NET 的不断发展,JsonSerializer 有望在性能、功能扩展性等方面进一步提升,以满足日益复杂的应用需求。

@JsonSerialize(using = ToStringSerializer.class)和@JsonSerialize注解的使用方法 关于这个注解的方法,可以自己定义class,作为using的值来使用。/*** 订单创建时间*/这个的意义就是当转成json时,把时间转成秒的格式。@Override创建一个注解类,统一帮助我们实现对BigDecimal此类型字段数值的封装操作if (value!= null) {} else {创建完注解类后,具体什么字段需要保留两位有效数字,就在对应的字段上加上此注解最后返回的值就是保留两位有效数字的。 阅读详情

相关推荐

序列化和反序列化

在 Jackson 中,自定义序列化器和反序列化器可以通过继承和类来实现。以下是如何定义和使用自定义序列化器和反序列化器的详细步骤。定义自定义序列化器继承类并重写serialize方法。

我这个代码你能看懂吗? 1199

JsonSerializer<T>类详细介绍及使用方式

是一个泛型类,用于自定义对象在序列化为JSON字符串时的行为。它允许您以自定义的方式控制对象序列化过程,包括属性命名、值格式、忽略字段等。不同的JSON库和框架提供了不同的实现方式。

算命de博客 4650

C# JSON反序列化:JObject强制转换异常分析与解决方案

JSON作为现代应用数据交换的核心格式,其序列化与反序列化是软件开发中的基础操作。在C#生态中,Newtonsoft.Json(Json.NET)通过将JSON字符串转换为内存对象实现数据绑定,这一过程涉及类型系统映射与数据格式解析。当开发者尝试将动态JSON容器JObject直接强制转换为自定义强类型时,会触发InvalidCastException,这源于C#强类型系统与动态数据结构间的本质差异。理解JObject作为动态查询容器的本质,掌握ToObject<T>()方法进行安全转换,能有效避免类型转换

weixin_33770878的博客 481

JsonSerializer 类

定义 命名空间: System.Text.Json 程序集: System.Text.Json.dll 提供将对象或值类型序列化为 JSON 以及将 JSON 反序列化为对象或值类型的功能。 public static class JsonSerializer 继承 Object ---》 JsonSerializer 我踩过的坑 public class User { public int Id { get; set; } } static void Main(stri..

huxyc的博客 5932

Newtonsoft.Json实战指南:C# JSON处理核心技巧与避坑

JSON作为现代数据交换的通用格式,其序列化与反序列化是软件开发中的基础技术。序列化将对象转换为可传输或存储的字符串,反序列化则将其还原为内存中的对象实例,这一过程在Web API调用、配置文件解析和数据库交互等场景中至关重要。Newtonsoft.Json以其卓越的灵活性和容错性,成为处理复杂、非标准JSON数据的首选工具,尤其在对接历史系统或第三方不规范接口时优势明显。通过掌握其核心API与高级特性,开发者能高效应对物联网(如MQTT消息解析)、TVBox配置处理等实际工程挑战,确保数据处理的鲁棒性与开

ithome 512

深入Newtonsoft.Json源码解析及其高级应用

在处理复杂对象或特定数据类型时,标准的序列化行为可能无法满足需求。这时,可以通过添加自定义转换器()来实现特定的序列化和反序列化逻辑。例如,一个日期时间类型可能需要特定的格式化规则:// 自定义反序列化逻辑// 自定义序列化逻辑// 在设置中使用自定义转换器在.NET中处理JSON数据时,扮演了关键角色。是Newtonsoft.Json库中一个强大的接口,允许开发者对序列化和反序列化过程进行精细控制。

weixin_42443533的博客 941

深入理解Newtonsoft.Json库的内部序列化和反序列化过程详解

Newtonsoft.Json是一个常用的JSON序列化和反序列化库,我相信很多人在使用Newtonsoft.Json进行序列化和反序列化操作的时候,都会使用如下代码,那么有没有思考过他们内部是怎样实现的一个过程,它的核心原理是什么?

dotnet研习社 2580

Zemax非序列模式新手入门:从零搭建一个抛物面反射镜系统(含灯丝光源与探测器设置)

本文详细介绍了如何在Zemax非序列模式下从零搭建抛物面反射镜系统,包括灯丝光源配置、反射镜建模和探测器设置等关键步骤。通过实战指南,帮助光学设计新手快速掌握非序列模式的应用技巧,特别适合处理复杂光线传播场景如反射镜系统和杂散光分析。

weixin_28717431的博客 436

攻克.NET反序列化难题:JsonSerializer异常排查与性能优化指南

在.NET应用开发中,JsonSerializer(JSON序列化器)作为处理JSON数据的核心组件,其稳定性直接影响系统可靠性。本文基于dotnet/runtime项目源码分析,从异常排查、性能调优到最佳实践,提供一套系统化解决方案,帮助开发者快速定位并解决反序列化问题。 ## 反序列化常见问题分类与现象 JsonSerializer反序列化失败通常表现为三种典型错误:**类型不匹配异常**...

gitblog_01076的博客 388

思科 MIB 库

思科 MIB

m0_54931486的博客 770

如何程序化的将 Wire 文件转换成 STEP、CATIA、DWG、NX、FBX 等格式

Wire 文件是专有格式,只有 Autodesk Alias 软件能够直接打开和编辑。 虽然可以在 Alias 软件中手动打开文件并导出为 STEP,但在实际工作中,经常会遇到需要转换数十甚至数百个文件的场景。如果每次都手动操作软件进行转换,不仅效率低下,还容易出错,批量场景下会非常麻烦。因此,程序化、自动化的转换方案变得至关重要。

weixin_44211633的博客 450

.NET 9 AOT发布序列化反序列化报错System.Text.Json.JsonSerializer和Newtonsoft.Json反射问题踩坑实录

.NET 9 AOT发布序列化反序列化报错System.Text.Json.JsonSerializer和Newtonsoft.Json反射问题踩坑实录

吴所畏惧 4218

块存储:AIO的直接写流程注释

提交io流程中aio_write之前函数的注释,可参考“块存储:AIO的直接读流程注释”。

yiyeguzhou100的专栏 1333

C# System.Text.Json实现高效JSON序列化与反序列化

在.NET生态中,JSON作为主流数据交换格式,其处理效率直接影响应用性能。自.NET Core 3.0引入System.Text.Json以来,开发者拥有了一个高性能、低内存分配的官方JSON解决方案。本文将深入解析其核心功能,助您掌握JSON处理的最佳实践。

xienda的博客 1419

OpenClaw实战系列02:企业微信接入完全指南

本文详细介绍了如何将OpenClaw与企业微信对接,实现智能机器人功能。主要内容包括:企业微信侧创建智能机器人或自建应用,获取必要凭证和权限;OpenClaw侧安装配置企业微信插件,设置通信通道;完成双向验证并进行功能测试。文章提供了详细的配置步骤、常见问题排查方法和进阶玩法,帮助用户在30分钟内完成对接。关键点包括:确保URL可访问、Token一致、网关正常运行,以及针对不同部署环境(云服务器/内网)的配置差异。

PeterPan的博客 3812

SAP_SD模块_SAP 消息号VF501(科目确定期间出错)

摘要: SAP SD模块中执行VF02销售开票时出现“科目确定期间出错”(VF501)问题,主要原因是系统无法找到匹配的总账科目。解决方案包括:检查物料主数据和客户主数据中的科目分配组是否维护,核对发票中的对应字段,并通过VKOA事务代码分析科目确定逻辑。若定价过程中配置的科目代码(如Z01)未在VKOA中完整映射(如缺少H1+S5+Z01组合),则会导致内部价格无法关联总账科目。需在SPRO路径下完善科目代码分配配置,确保定价类型与科目代码匹配。本文提供了详细的排查步骤和配置方法,帮助解决开票过账错误。

我小时候很黑的博客 354

反序列化漏洞原理与防御:从Java CC链到Fastjson的实战解析

序列化与反序列化是计算机科学中实现对象持久化与网络传输的核心机制,其本质是将内存中的复杂数据结构转换为可存储或传输的线性格式(如字节流、JSON),并在需要时重建为原始对象。这一过程依赖于对象的类定义,若反序列化器不加验证地执行不可信数据中的指令,便会模糊数据与代码的边界,导致程序执行攻击者控制的任意代码,从而引发严重的安全风险。其技术价值在于高效的数据交换,但错误实现会带来远程代码执行、权限提升等严重后果,广泛应用于RPC通信、Session存储、缓存系统等场景。本文聚焦于反序列化漏洞这一“定时炸弹”,深

weixin_33991418的博客 326

【C++】开源:cpp-httplib HTTP协议库配置与使用

cpp-httplib HTTP协议库配置与使用

DevFrank的博客 5540

.NET Runtime序列化技术:JSON、XML、Binary序列化

在分布式系统、微服务架构和云原生应用日益普及的今天,高效可靠的数据序列化(Serialization)技术已成为软件开发的核心需求。.NET Runtime作为微软跨平台运行时环境,提供了三种主流的序列化方案:高性能的JSON序列化、传统的XML序列化以及高效的二进制序列化。 你是否曾面临这样的挑战? - 微服务间数据传输性能瓶颈 - 不同系统间的数据格式兼容性问题 - 安全敏感数据的序列化...

gitblog_00005的博客 577

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

JSON序列化实战:Newtonsoft.Json核心原理与企业级应用

JSON作为轻量级数据交换格式,是Web API、微服务和前后端通信的事实标准。其本质是定义数据契约的结构化文本协议,序列化与反序列化过程涉及类型映射、命名策略、时区处理、循环引用和安全边界等关键原理。掌握这些机制,不仅能规避Unexpected token、Cannot deserialize等高频异常,更能提升API稳定性、跨系统兼容性与云原生环境下的内存效率。本文聚焦Newtonsoft.Json(Json.NET)在.NET生态中的不可替代性——从DateTime时区控制、SnakeCase命名适配

chuji3953的博客 391

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

C# JSON反序列化:解决JObject无法转换为强类型模型的InvalidCastException

JSON作为现代应用数据交换的核心格式,其序列化与反序列化是开发中的基础操作。在C#中,Newtonsoft.Json库通过将JSON字符串转换为强类型对象,实现了类型安全的数据操作。然而,当反序列化结果的实际类型与预期不符时,常见的InvalidCastException错误便会出现,这通常是由于数据在传递过程中类型信息丢失或模型定义不匹配导致的。从工程实践角度看,这类问题不仅影响代码健壮性,还可能引发运行时异常。通过理解JObject的动态特性、掌握安全类型检查方法,并合理配置序列化设置,开发者可以构建

weixin_34175509的博客 365

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

5分钟快速上手:Newtonsoft.Json高效JSON处理完全指南

想要在.NET应用中快速处理JSON数据吗?Newtonsoft.Json(也称为Json.NET)是.NET平台最流行的高性能JSON框架!无论你是开发Web API、移动应用还是桌面软件,这个强大的库都能帮你轻松实现JSON的序列化和反序列化。😊 ## 为什么选择Newtonsoft.Json? Newtonsoft.Json是一个成熟稳定的JSON处理库,在.NET生态系统中被广泛使用

gitblog_00744的博客 504

C# JSON序列化实战:Newtonsoft.Json从入门到性能优化

JSON(JavaScript Object Notation)作为一种轻量级数据交换格式,已成为现代软件开发中数据序列化的标准。其核心原理是将结构化数据转换为文本格式,实现跨平台、跨语言的数据交换。在C#技术栈中,JSON序列化是实现Web API通信、配置文件解析和数据持久化的关键技术。Newtonsoft.Json(Json.NET)凭借其卓越的灵活性和丰富的功能,成为处理复杂序列化场景的行业标杆,尤其在处理动态数据结构、自定义格式和遗留系统集成方面展现出独特价值。本文聚焦于**MQTT服务器**数据

weixin_34082854的博客 407

快速集成强大的JSON处理工具:Newtonsoft.Json.dll全面解析

在.NET开发领域,处理JSON数据几乎是每个项目不可或缺的一部分。对于那些寻找高效、稳定解决方案的开发者来说,`Newtonsoft.Json.dll`无疑是首选。本文旨在深入介绍这一神器,不仅让你了解如何轻松获得它,还剖析其背后的技术力量,探讨应用场景,并突出其显著特点,引导你步入JSON处理的新境界。 ## 项目介绍 **Newtonsoft.Json.dll** 是一个广泛应用于.NE

gitblog_09726的博客 719

告别JSON解析烦恼:.NET MAUI中System.Text.Json的5个高级技巧

在.NET MAUI跨平台应用开发中,JSON数据处理是一项核心任务。无论是与后端API交互、存储本地数据,还是处理配置文件,高效的JSON解析都能显著提升应用性能和开发效率。本文将分享5个基于System.Text.Json的高级技巧,帮助你轻松应对复杂JSON场景,让数据处理变得简单高效。 ## 1. 零分配流式JSON反序列化:处理大型数据集的终极方案 当处理来自网络的大型JSON数据流

gitblog_00245的博客 798
上一篇: 深度揭秘.NET中HttpClient的复用机制:性能优化与资源管理
下一篇: 深度解读.NET中的IL(中间语言):理解编译与运行机制的桥梁
步步为营DotNet
博客等级 码龄1年 295粉丝 286原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值