本文还有配套的精品资源,点击获取
简介:Newtonsoft.Json是C#开发中最流行的JSON处理类库,广泛应用于.***项目中,提供序列化、反序列化、格式化、动态解析等多种功能。该库通过丰富的API和灵活的配置选项,极大提升了处理JSON数据的效率和准确性。本内容通过代码实例详细讲解了其在对象序列化、动态类型解析、枚举处理、格式设置及高级功能中的使用方法,适合C#开发者快速掌握JSON数据的处理技巧,提升项目开发效率。
1. Newtonsoft.Json库简介
Newtonsoft.Json,又称 Json.***,是由 James Newton-King 开发的开源 JSON 框架,自 2006 年发布以来,已成为 .*** 平台最广泛使用的 JSON 序列化与反序列化库。它不仅支持标准的 JSON 格式处理,还提供了强大的扩展能力,如自定义序列化器、动态对象解析、LINQ to JSON 查询等功能。
其优势体现在:高性能、易用性、支持动态类型与泛型、兼容 .*** Framework 与 .*** Core,并广泛应用于 Web API、微服务、数据持久化等场景。相比 .*** 原生的 DataContractJsonSerializer 和 System.Text.Json ,Newtonsoft.Json 提供了更灵活的 API 设计和更丰富的功能集,因此在企业级项目中具有不可替代的地位。
2. JSON序列化基本操作
在现代C#开发中,JSON(JavaScript Object Notation)已经成为数据交换的标准格式。Newtonsoft.Json(又称Json.***)作为.***平台上最强大、最灵活的JSON处理库,广泛应用于Web API、微服务、前后端数据交互等场景。本章将深入讲解如何使用Newtonsoft.Json进行基本的JSON序列化操作,包括对象、集合、数组的序列化方法,以及在序列化过程中如何控制格式与行为,确保生成的JSON结构符合实际业务需求。
2.1 序列化对象为JSON字符串
序列化是指将一个C#对象转换为JSON格式的字符串,以便于在网络上传输或持久化存储。Newtonsoft.Json提供了简洁高效的API来完成这一操作。
2.1.1 使用JsonConvert.SerializeObject方法
JsonConvert.SerializeObject 是 Newtonsoft.Json 提供的最常用的方法,用于将任意C#对象转换为JSON字符串。其基本语法如下:
string json = JsonConvert.SerializeObject(object value);
示例代码:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Person person = new Person { Name = "Alice", Age = 30 };
string json = JsonConvert.SerializeObject(person);
Console.WriteLine(json);
输出结果:
{"Name":"Alice","Age":30}
代码逻辑分析:
-
Person类定义了两个属性:Name和Age。 - 创建了一个
Person实例并赋值。 - 使用
JsonConvert.SerializeObject方法将对象序列化为JSON字符串。 - 控制台输出结果为标准的JSON格式,键值对形式。
参数说明:
-
object value:需要序列化的对象,可以是任意类型。 - 还可以传入可选参数
Formatting、TypeNameHandling等,用于控制输出格式和类型信息。
2.1.2 设置格式化选项(Formatting)
默认情况下, JsonConvert.SerializeObject 会输出紧凑格式的JSON字符串,不带缩进和换行。在调试或日志输出时,我们通常希望JSON具有良好的可读性。可以通过 Formatting 参数来控制格式。
示例代码:
string formattedJson = JsonConvert.SerializeObject(person, Formatting.Indented);
Console.WriteLine(formattedJson);
输出结果:
{
"Name": "Alice",
"Age": 30
}
参数说明:
-
Formatting.None(默认):输出紧凑格式。 -
Formatting.Indented:输出带缩进和换行的格式,便于阅读。
应用场景:
- 调试日志:使用
Indent格式更易读。 - 生产环境:使用默认格式节省带宽和存储空间。
2.2 序列化集合与数组
除了单个对象,我们经常需要序列化集合(如列表、字典)或数组。Newtonsoft.Json 对这些结构提供了原生支持,能够自动识别并正确转换。
2.2.1 列表、字典等集合的序列化方式
列表(List)示例:
List<Person> people = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 25 }
};
string jsonList = JsonConvert.SerializeObject(people, Formatting.Indented);
Console.WriteLine(jsonList);
输出结果:
[
{
"Name": "Alice",
"Age": 30
},
{
"Name": "Bob",
"Age": 25
}
]
字典(Dictionary)示例:
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "Math", 90 },
{ "English", 85 }
};
string jsonDict = JsonConvert.SerializeObject(scores, Formatting.Indented);
Console.WriteLine(jsonDict);
输出结果:
{
"Math": 90,
"English": 85
}
代码分析:
-
List<T>和Dictionary<TKey, TValue>都可以直接序列化。 - 输出的JSON结构分别对应数组和对象,保持了原集合的语义。
2.2.2 数组类型与嵌套结构的处理
数组序列化示例:
int[] numbers = { 1, 2, 3, 4, 5 };
string jsonArray = JsonConvert.SerializeObject(numbers);
Console.WriteLine(jsonArray);
输出结果:
[1,2,3,4,5]
嵌套结构示例:
public class Address
{
public string City { get; set; }
public string ZipCode { get; set; }
}
public class Employee
{
public string Name { get; set; }
public Address HomeAddress { get; set; }
}
Employee emp = new Employee
{
Name = "Charlie",
HomeAddress = new Address { City = "Shanghai", ZipCode = "200000" }
};
string nestedJson = JsonConvert.SerializeObject(emp, Formatting.Indented);
Console.WriteLine(nestedJson);
输出结果:
{
"Name": "Charlie",
"HomeAddress": {
"City": "Shanghai",
"ZipCode": "200000"
}
}
分析说明:
- 嵌套对象结构在JSON中表现为对象嵌套。
- Newtonsoft.Json 会自动处理嵌套层级,无需手动拆分。
2.3 控制序列化行为
在实际开发中,我们往往需要对序列化行为进行控制,比如忽略空值、设置默认值、忽略某些字段等。Newtonsoft.Json 提供了丰富的配置选项来满足这些需求。
2.3.1 忽略空值与默认值
有时我们希望在序列化时忽略值为 null 或默认值的属性,以减少输出体积。
示例代码:
public class Product
{
public string Name { get; set; }
public decimal? Price { get; set; }
public string Description { get; set; }
}
Product product = new Product { Name = "Laptop" };
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
string json = JsonConvert.SerializeObject(product, Formatting.Indented, settings);
Console.WriteLine(json);
输出结果:
{
"Name": "Laptop"
}
参数说明:
-
NullValueHandling.Ignore:忽略值为 null 的属性。 -
DefaultValueHandling.Ignore:忽略值为默认值的属性(如 int=0、string=null 等)。
2.3.2 自定义序列化设置(JsonSerializerSettings)
通过 JsonSerializerSettings 可以对序列化过程进行更细粒度的控制,如类型处理、日期格式、循环引用处理等。
示例代码:
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
DateFormatString = "yyyy-MM-dd HH:mm:ss",
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string json = JsonConvert.SerializeObject(product, Formatting.Indented, settings);
Console.WriteLine(json);
参数说明:
| 参数名称 | 说明 |
|---|---|
TypeNameHandling |
控制是否在JSON中包含类型信息 |
DateFormatString |
自定义日期时间格式 |
PreserveReferencesHandling |
控制是否保留对象引用,防止重复 |
ReferenceLoopHandling |
控制如何处理循环引用 |
mermaid 流程图:
graph TD
A[开始序列化] --> B{是否为复杂对象?}
B -->|是| C[检查引用循环]
C --> D[根据设置处理引用]
B -->|否| E[直接序列化属性]
E --> F[应用格式化设置]
F --> G[输出JSON字符串]
实际应用场景:
- 微服务间通信:启用
TypeNameHandling以保留类型信息。 - 日志记录:设置
DateFormatString统一日期格式。 - 图形结构数据(如树形结构):启用
PreserveReferencesHandling和ReferenceLoopHandling防止循环引用导致堆栈溢出。
通过本章的学习,读者已经掌握了 Newtonsoft.Json 中对象、集合、数组的基本序列化方法,并了解了如何通过参数控制序列化的格式与行为。这些内容为后续深入学习反序列化、自定义序列化等高级操作打下了坚实的基础。
3. JSON反序列化基本操作
JSON反序列化是将结构化的 JSON 数据还原为 C# 对象的过程。Newtonsoft.Json 提供了灵活而强大的反序列化机制,能够处理从简单对象到复杂集合类型的各种场景。掌握反序列化操作对于构建数据驱动的应用程序至关重要,尤其是在 RESTful API 交互、数据持久化与远程服务通信中。
本章将围绕反序列化的核心操作展开,从基础的 JsonConvert.DeserializeObject 方法开始,逐步深入探讨集合与泛型类型的反序列化方式,并最终分析反序列化过程中常见的异常场景及应对策略。
3.1 反序列化为强类型对象
反序列化的核心目标是将 JSON 字符串转换为 C# 中具有明确结构的对象。Newtonsoft.Json 提供了简洁的 API 接口,使开发者能够以类型安全的方式完成这一过程。
3.1.1 使用 JsonConvert.DeserializeObject 方法
JsonConvert.DeserializeObject 是 Newtonsoft.Json 提供的最常用方法之一,用于将 JSON 字符串转换为指定类型的 C# 对象。
示例代码:
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
string json = "{\"Name\":\"张三\",\"Age\":25}";
Person person = JsonConvert.DeserializeObject<Person>(json);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
代码解析:
- 第 1 行 :引入 Newtonsoft.Json 命名空间。
- 第 3-7 行 :定义一个
Person类,包含Name和Age两个属性。 - 第 9 行 :定义一个 JSON 字符串。
- 第 10 行 :调用
JsonConvert.DeserializeObject<T>方法,将 JSON 字符串转换为Person类型的实例。 - 第 12 行 :输出解析后的对象属性值。
执行结果:
Name: 张三, Age: 25
参数说明:
-
T:泛型参数,表示目标类型。 -
value:需要反序列化的 JSON 字符串。 -
settings(可选):JsonSerializerSettings对象,用于配置反序列化行为(如日期格式、命名策略等)。
3.1.2 类型匹配与属性映射规则
Newtonsoft.Json 在反序列化时遵循一定的映射规则,确保 JSON 字段与 C# 类型属性之间正确匹配:
| JSON 字段名称 | C# 属性名称 | 是否匹配 | 说明 |
|---|---|---|---|
Name |
Name |
✅ | 完全匹配 |
name |
Name |
✅ | 默认忽略大小写 |
UserName |
Name |
❌ | 名称不一致 |
ExtraField |
无对应属性 | ✅ | 忽略未定义字段 |
示例说明:
string json = "{\"name\":\"李四\",\"Gender\":\"男\"}";
Person person = JsonConvert.DeserializeObject<Person>(json);
尽管 name 小写,但由于默认设置中 ContractResolver 为 CamelCasePropertyNamesContractResolver 或 DefaultContractResolver ,因此可以成功映射至 Name 属性。而 Gender 字段因 Person 类中无对应属性,会被忽略。
3.2 反序列化集合与泛型类型
在实际开发中,常常需要将 JSON 数据反序列化为集合类型,如 List<T> 、 Dictionary<TKey, TValue> 或嵌套的泛型结构。Newtonsoft.Json 对此类场景提供了良好的支持。
3.2.1 列表、字典等集合的反序列化
示例:反序列化为 List
string json = "[{\"Name\":\"Alice\",\"Age\":30},{\"Name\":\"Bob\",\"Age\":28}]";
List<Person> people = JsonConvert.DeserializeObject<List<Person>>(json);
该代码将 JSON 数组转换为 List<Person> 类型。
示例:反序列化为 Dictionary
string json = "{\"1001\":{\"Name\":\"Tom\",\"Age\":22},\"1002\":{\"Name\":\"Jerry\",\"Age\":24}}";
Dictionary<string, Person> peopleDict = JsonConvert.DeserializeObject<Dictionary<string, Person>>(json);
此代码将 JSON 对象转换为以字符串为键、 Person 对象为值的字典。
支持的集合类型包括:
| 类型 | 描述 |
|---|---|
List<T> |
动态数组 |
IEnumerable<T> |
可枚举集合 |
Dictionary<TKey, TValue> |
键值对集合 |
Queue<T> |
队列结构 |
HashSet<T> |
无重复集合 |
SortedSet<T> |
排序集合 |
注意事项:
- 集合中的元素类型必须是可反序列化的类或结构体。
- 如果 JSON 中包含的字段与集合元素类型不匹配,将自动忽略。
3.2.2 泛型对象与嵌套结构的处理
示例:反序列化嵌套泛型对象
public class Order<T>
{
public int OrderId { get; set; }
public T Item { get; set; }
}
string json = "{\"OrderId\":101,\"Item\":{\"Name\":\"iPhone\",\"Price\":999}}";
var order = JsonConvert.DeserializeObject<Order<Product>>(json);
其中 Product 类定义如下:
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
输出结果:
Console.WriteLine($"Order ID: {order.OrderId}, Product: {order.Item.Name}, Price: {order.Item.Price}");
Order ID: 101, Product: iPhone, Price: 999
反序列化嵌套结构流程图(mermaid):
graph TD
A[JSON字符串] --> B[Newtonsoft.Json反序列化]
B --> C{是否为嵌套结构}
C -->|是| D[递归解析内部对象]
C -->|否| E[直接映射属性]
D --> F[生成泛型对象实例]
E --> F
F --> G[返回强类型对象]
3.3 反序列化时的异常处理
在实际应用中,由于数据格式错误、字段缺失或类型不匹配等原因,反序列化操作可能会失败。合理地处理这些异常对于构建健壮的应用程序至关重要。
3.3.1 处理字段缺失与类型不匹配
示例:字段缺失处理
string json = "{\"Name\":\"Alice\"}"; // 缺少 Age 字段
Person person = JsonConvert.DeserializeObject<Person>(json);
在这种情况下, person.Age 将被赋值为默认值 0 ,因为 Age 是 int 类型。若希望忽略未提供字段,可使用 DefaultValueHandling 设置:
var settings = new JsonSerializerSettings
{
DefaultValueHandling = DefaultValueHandling.Ignore
};
Person person = JsonConvert.DeserializeObject<Person>(json, settings);
示例:类型不匹配处理
string json = "{\"Name\":\"Bob\",\"Age\":\"twenty\"}"; // Age 字段为字符串
try
{
Person person = JsonConvert.DeserializeObject<Person>(json);
}
catch (JsonSerializationException ex)
{
Console.WriteLine("反序列化失败:" + ex.Message);
}
输出结果:
反序列化失败:无法将字符串转换为整数
3.3.2 错误信息捕获与调试技巧
使用 JsonReaderException 和 JsonSerializationException 捕获具体的错误类型,有助于快速定位问题。
示例:捕获 JSON 格式错误
string invalidJson = "{\"Name\":\"Alice\""; // 缺少右括号
try
{
Person person = JsonConvert.DeserializeObject<Person>(invalidJson);
}
catch (JsonReaderException ex)
{
Console.WriteLine("JSON 格式错误:" + ex.Message);
}
输出结果:
JSON 格式错误:结束字符 'EOF' 之前缺少 '}'。
异常类型与适用场景表格:
| 异常类型 | 触发条件 | 说明 |
|---|---|---|
JsonReaderException |
JSON 格式错误 | 如缺失引号、括号不匹配 |
JsonSerializationException |
类型转换失败、字段缺失 | 如字符串转整数失败 |
JsonException |
所有 Newtonsoft.Json 异常基类 | 用于统一捕获 |
建议的异常处理流程(mermaid):
graph TD
A[尝试反序列化JSON] --> B{是否成功}
B -->|是| C[返回对象]
B -->|否| D[捕获异常类型]
D --> E[判断是否为JSON格式错误]
D --> F[判断是否为类型转换错误]
E --> G[提示JSON语法错误]
F --> H[提示字段类型不匹配]
本章通过详细的代码示例与流程分析,深入讲解了 Newtonsoft.Json 在反序列化方面的核心功能与常见问题处理方式。掌握了这些内容后,开发者能够更加自信地处理从简单对象到复杂集合结构的 JSON 数据转换任务,并具备良好的异常处理能力,为构建稳定可靠的数据交互系统打下坚实基础。
4. 自定义JSON格式设置
在现代Web开发中,不同系统、平台或接口之间往往要求JSON数据具有特定的格式规范。Newtonsoft.Json(Json.***)不仅提供了基础的序列化与反序列化功能,还允许开发者通过丰富的配置选项来自定义JSON输出格式。本章将深入探讨如何通过命名策略、属性名称映射、日期与数字格式化等手段,灵活控制JSON的输出样式,以满足实际项目中的格式一致性要求。
4.1 自定义属性名称与命名策略
在实际项目中,不同的后端和前端系统往往使用不同的命名风格,例如前端常用 camelCase ,而后端可能使用 PascalCase 。Newtonsoft.Json 提供了多种方式来统一属性名称的输出格式。
4.1.1 CamelCase与PascalCase转换
Newtonsoft.Json 提供了 ContractResolver 机制,可以用于统一属性名称的大小写风格。
示例:使用 CamelCasePropertyNamesContractResolver
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var user = new User
{
FirstName = "Alice",
LastName = "Smith"
};
string json = JsonConvert.SerializeObject(user, settings);
Console.WriteLine(json);
输出:
{
"firstName": "Alice",
"lastName": "Smith"
}
逐行解析:
-ContractResolver设置为CamelCasePropertyNamesContractResolver,所有属性名自动转换为 camelCase。
-JsonConvert.SerializeObject将对象序列化为 JSON 字符串。
- 输出结果中,FirstName变为firstName,符合前端命名规范。
示例:使用 PascalCase(默认)
如果不设置 ContractResolver ,默认使用 PascalCase 输出:
string json = JsonConvert.SerializeObject(user);
Console.WriteLine(json);
输出:
{
"FirstName": "Alice",
"LastName": "Smith"
}
参数说明:
-ContractResolver是 Newtonsoft.Json 控制属性序列化方式的核心机制。
- 默认使用DefaultContractResolver,保留类属性的原名。
4.1.2 使用 JsonProperty 特性控制字段名
当需要对某些字段进行特别命名时,可以使用 [JsonProperty] 特性手动指定 JSON 字段名。
示例代码:
public class User
{
[JsonProperty("userName")]
public string FirstName { get; set; }
[JsonProperty("surname")]
public string LastName { get; set; }
}
string json = JsonConvert.SerializeObject(new User
{
FirstName = "Bob",
LastName = "Johnson"
});
Console.WriteLine(json);
输出:
{
"userName": "Bob",
"surname": "Johnson"
}
逐行解析:
-JsonProperty特性强制指定字段名。
- 即使启用CamelCasePropertyNamesContractResolver,此字段仍保持指定名称。应用场景:
- 与第三方接口对接时字段名不一致。
- 数据库字段与 JSON 字段需保持映射一致性。
总结命名策略使用场景:
| 使用方式 | 适用场景 | 是否推荐 |
|---|---|---|
| CamelCasePropertyNamesContractResolver | 前后端交互、REST API 输出 | ✅ |
| PascalCase(默认) | 后端服务内部通信 | ✅ |
| JsonProperty 特性 | 需要精确命名字段 | ✅ |
4.2 控制日期与数字格式
在 JSON 数据中,日期和数字格式往往需要与接口文档保持一致。Newtonsoft.Json 提供了多种方式来控制日期格式、数字精度与格式字符串。
4.2.1 日期格式化(DateTime 与 ISO 格式)
默认情况下,Newtonsoft.Json 使用 ISO 8601 格式输出日期:
"2025-04-05T12:34:56.789Z"
自定义日期格式:
var settings = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
var obj = new
{
CreatedAt = new DateTime(2025, 4, 5, 12, 34, 56)
};
string json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
Console.WriteLine(json);
输出:
{
"CreatedAt": "2025-04-05 12:34:56"
}
逐行解析:
-DateFormatString设置自定义日期时间格式。
-Formatting.Indented用于美化输出格式,便于调试。
- 输出格式由默认的 ISO 转换为yyyy-MM-dd HH:mm:ss。
ISO 8601 与本地时间格式转换示例:
| 设置 | 输出示例 | 说明 |
|---|---|---|
| 不设置 | "2025-04-05T12:34:56.789Z" |
UTC 时间 |
DateFormatString = "yyyy-MM-ddTHH:mm:ss" |
"2025-04-05T12:34:56" |
本地时间格式 |
DateTimeZoneHandling = DateTimeZoneHandling.Local |
"2025-04-05T12:34:56+08:00" |
包含时区信息 |
4.2.2 数值类型与格式字符串设置
Newtonsoft.Json 支持对数值类型进行格式化输出,例如保留小数位数、百分比格式等。
示例:格式化浮点数
var obj = new
{
Price = 99.999
};
var settings = new JsonSerializerSettings
{
FloatFormatHandling = FloatFormatHandling.String,
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(obj, "0.00", settings);
Console.WriteLine(json);
输出:
{
"Price": "99.99"
}
参数说明:
-FloatFormatHandling.String表示将数值格式化为字符串。
-"0.00"表示保留两位小数。
- 适用于需要精确显示货币、百分比等场景。
数值格式化对比表:
| 设置 | 输入值 | 输出值 | 说明 |
|---|---|---|---|
| 默认 | 99.999 |
99.999 |
浮点数原样输出 |
"0.00" + FloatFormatHandling.String |
99.999 |
"99.99" |
保留两位小数 |
"P" |
0.85 |
"85.00%" |
百分比格式 |
4.3 忽略特定字段与条件序列化
在实际开发中,有时需要忽略某些字段,或者根据特定条件决定是否序列化字段。Newtonsoft.Json 提供了 [JsonIgnore] 和 ShouldSerialize 方法两种方式来实现这一需求。
4.3.1 使用 JsonIgnore 特性忽略字段
对于不希望出现在 JSON 输出中的字段,可以直接使用 [JsonIgnore] 特性进行忽略。
示例:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
[JsonIgnore]
public string Password { get; set; }
}
var user = new User
{
FirstName = "John",
LastName = "Doe",
Password = "secret123"
};
string json = JsonConvert.SerializeObject(user, Formatting.Indented);
Console.WriteLine(json);
输出:
{
"FirstName": "John",
"LastName": "Doe"
}
逐行解析:
-Password属性被标记为[JsonIgnore],序列化时被跳过。
- 保证敏感信息不会被意外暴露。
4.3.2 条件性序列化(ShouldSerialize 方法)
有时我们希望根据运行时的逻辑来决定是否序列化某个字段。Newtonsoft.Json 支持通过 ShouldSerialize{PropertyName} 方法实现条件序列化。
示例:
public class Product
{
public string Name { get; set; }
public decimal? Discount { get; set; }
public bool ShouldSerializeDiscount()
{
return Discount.HasValue && Discount > 0;
}
}
var product1 = new Product
{
Name = "Laptop",
Discount = 0.1m
};
var product2 = new Product
{
Name = "Mouse",
Discount = 0
};
string json1 = JsonConvert.SerializeObject(product1, Formatting.Indented);
string json2 = JsonConvert.SerializeObject(product2, Formatting.Indented);
Console.WriteLine(json1);
Console.WriteLine(json2);
输出:
// json1
{
"Name": "Laptop",
"Discount": 0.1
}
// json2
{
"Name": "Mouse"
}
逐行解析:
-ShouldSerializeDiscount方法返回true时才输出Discount字段。
-product2的Discount为0,因此未被序列化。
条件序列化流程图(mermaid):
graph TD
A[ShouldSerialize{PropertyName}方法] --> B{返回true?}
B -->|是| C[序列化该字段]
B -->|否| D[忽略该字段]
应用场景:
- 敏感字段(如密码)需始终忽略。
- 可选字段(如折扣、扩展信息)根据业务逻辑决定是否输出。
小结:自定义 JSON 格式设置的应用价值
本章通过命名策略、日期与数字格式控制、字段忽略与条件序列化等手段,展示了如何灵活控制 JSON 输出样式。这些功能不仅增强了接口数据的一致性,也为前后端协作、接口文档一致性提供了有力支持。
在实际项目开发中,合理使用这些自定义设置,可以有效减少数据转换的复杂性,提升代码可维护性,并降低接口对接的出错率。下一章我们将继续深入探讨动态对象与匿名类型的解析技巧,进一步提升 JSON 处理的灵活性。
5. 动态对象与匿名类型解析
在实际的C#开发中,尤其是与RESTful API、微服务、JSON数据源交互的场景中,常常会遇到结构不固定或临时需要解析的JSON数据。在这种情况下,使用静态类型的反序列化方式不仅代码冗余,而且不够灵活。Newtonsoft.Json 提供了对 dynamic 类型和 匿名类型(Anonymous Type) 的良好支持,使得我们可以更加灵活地处理动态JSON结构。
本章将深入探讨如何使用 dynamic 类型解析JSON数据,如何利用匿名类型进行临时数据绑定,以及如何结合LINQ to JSON进行更高级的动态查询与数据筛选。
5.1 使用dynamic解析JSON
dynamic 是 C# 4.0 引入的一个动态类型,它在编译时不进行类型检查,而是在运行时解析。这种方式非常适合处理结构不确定的JSON数据。
Newtonsoft.Json 提供了将 JSON 字符串转换为 dynamic 对象的能力,主要通过 JObject.Parse 方法结合 dynamic 类型实现。
5.1.1 JObject与dynamic的转换方式
我们可以使用 JObject.Parse() 方法将 JSON 字符串解析为 JObject ,然后通过 ToObject<dynamic>() 或者直接使用 JsonConvert.DeserializeObject<dynamic>() 转换为动态类型。
示例代码:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
string json = @"
{
""name"": ""Alice"",
""age"": 28,
""address"": {
""city"": ""Shanghai"",
""zip"": ""200000""
},
""hobbies"": [""reading"", ""coding"", ""traveling""]
}";
// 方式一:使用 JObject.Parse 转换为 dynamic
JObject jObject = JObject.Parse(json);
dynamic dynamicData = jObject;
Console.WriteLine($"Name: {dynamicData.name}");
Console.WriteLine($"City: {dynamicData.address.city}");
Console.WriteLine($"First Hobby: {dynamicData.hobbies[0]}");
// 方式二:直接使用 JsonConvert.DeserializeObject<dynamic>
dynamic directDynamic = JsonConvert.DeserializeObject<dynamic>(json);
Console.WriteLine($"Name: {directDynamic.name}");
代码逻辑分析:
- 第一步:定义一个包含嵌套结构和数组的 JSON 字符串。
- 第二步:使用
JObject.Parse(json)解析为 JObject,然后通过隐式转换赋值给dynamic。 - 第三步:访问动态对象的属性时,语法简洁,无需强类型定义。
- 第四步:也可以直接使用
JsonConvert.DeserializeObject<dynamic>,效果相同。
参数说明:
| 方法 | 说明 |
|---|---|
JObject.Parse(json) |
将 JSON 字符串解析为 JObject 对象 |
dynamic 类型 |
允许在运行时动态访问属性和方法 |
ToObject<dynamic>() |
将 JObject 转换为动态类型对象 |
使用场景:
- 临时解析 JSON 数据,不关心类型结构。
- 快速调试 API 返回的数据结构。
- 构建轻量级的数据处理流程。
5.1.2 动态访问属性与嵌套结构
在处理嵌套结构时, dynamic 表现出强大的灵活性。可以轻松访问嵌套对象、数组、字典等结构。
示例代码:
string nestedJson = @"
{
""user"": {
""id"": 123,
""roles"": [
{ ""name"": ""admin"", ""level"": 5 },
{ ""name"": ""editor"", ""level"": 3 }
]
}
}";
dynamic nestedData = JsonConvert.DeserializeObject<dynamic>(nestedJson);
// 访问嵌套属性
Console.WriteLine($"User ID: {nestedData.user.id}");
// 遍历嵌套数组
foreach (var role in nestedData.user.roles)
{
Console.WriteLine($"Role: {role.name}, Level: {role.level}");
}
逻辑分析:
- 使用
dynamic可以直接访问嵌套对象user、roles数组。 - 数组中的每个元素也是
dynamic类型,可继续访问其属性。 - 不需要定义
User、Role等类,节省了代码量。
使用建议:
- 在不确定 JSON 结构或结构频繁变化时使用。
- 不适合在大型项目中广泛使用,因为缺乏编译时检查,容易引入运行时错误。
5.2 匿名类型的反序列化
在某些场景下,我们可能只需要临时使用一部分 JSON 数据,并不想定义完整的类结构。这时可以使用 匿名类型 (Anonymous Type) 来进行反序列化。
Newtonsoft.Json 支持将 JSON 字符串反序列化为匿名对象,前提是提供一个模板对象。
5.2.1 创建匿名对象模板
通过构造一个具有相同属性名的匿名对象作为模板, JsonConvert.DeserializeAnonymousType 方法可以根据该模板反序列化 JSON 数据。
示例代码:
string userJson = @"
{
""name"": ""Bob"",
""email"": ""bob@example.***"",
""age"": 30
}";
// 定义匿名类型模板
var userTemplate = new
{
name = string.Empty,
email = string.Empty,
age = 0
};
// 使用模板反序列化
var user = JsonConvert.DeserializeAnonymousType(userJson, userTemplate);
Console.WriteLine($"Name: {user.name}");
Console.WriteLine($"Email: {user.email}");
Console.WriteLine($"Age: {user.age}");
代码逻辑分析:
-
userTemplate是一个匿名类型,用于指定期望的字段结构。 -
JsonConvert.DeserializeAnonymousType根据模板结构将 JSON 映射到匿名对象。 - 反序列化后的
user对象是强类型的匿名对象,属性访问安全。
参数说明:
| 方法 | 说明 |
|---|---|
JsonConvert.DeserializeAnonymousType<T>(json, template) |
将 JSON 字符串反序列化为与模板一致的匿名类型对象 |
template |
一个匿名对象,用于定义目标结构 |
5.2.2 使用匿名类型进行临时数据绑定
匿名类型非常适合在不需要定义完整类的情况下绑定部分数据,比如在 MVC 视图模型、API 响应处理中。
示例代码(Web API 中使用):
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
[HttpGet]
public IActionResult GetUserInfo()
{
string json = "{\"name\":\"Charlie\",\"email\":\"charlie@example.***\"}";
var template = new { name = "", email = "" };
var userInfo = JsonConvert.DeserializeAnonymousType(json, template);
return Ok(userInfo);
}
}
说明:
- 在 Web API 中,返回匿名对象时,可以避免定义多余的数据模型类。
- 同时保持接口结构清晰,易于维护。
5.3 动态解析与LINQ结合应用
Newtonsoft.Json 提供了 LINQ to JSON 的 API,可以像操作集合一样操作 JSON 数据结构。结合 JObject 和 dynamic ,可以实现强大的动态查询能力。
5.3.1 JObject与LINQ to JSON的交互
JObject 和 JArray 支持 LINQ 查询语法,可以实现对 JSON 数据的过滤、投影、排序等操作。
示例代码:
string productsJson = @"
[
{ ""name"": ""Laptop"", ""price"": 1200, ""inStock"": true },
{ ""name"": ""Tablet"", ""price"": 600, ""inStock"": false },
{ ""name"": ""Smartphone"", ""price"": 800, ""inStock"": true }
]";
JArray products = JArray.Parse(productsJson);
// 使用 LINQ 查询库存为 true 的商品
var inStockProducts = from p in products
where (bool)p["inStock"] == true
orderby (int)p["price"] ascending
select new
{
Name = (string)p["name"],
Price = (int)p["price"]
};
foreach (var product in inStockProducts)
{
Console.WriteLine($"Product: {product.Name}, Price: {product.Price}");
}
逻辑分析:
- 使用
JArray.Parse解析 JSON 数组。 - 使用 LINQ 查询表达式筛选
inStock为true的商品。 - 对结果进行排序并投影为匿名类型。
- 最终输出符合条件的商品信息。
优势:
- 可以灵活地操作 JSON 数据,无需完全反序列化为对象。
- 支持排序、筛选、分组等高级操作。
5.3.2 构建动态查询与数据筛选逻辑
通过 JObject 与 dynamic 的结合,可以构建更复杂的动态查询逻辑。
示例代码:
string dataJson = @"
{
""users"": [
{ ""name"": ""David"", ""role"": ""admin"", ""active"": true },
{ ""name"": ""Eve"", ""role"": ""user"", ""active"": false },
{ ""name"": ""Frank"", ""role"": ""admin"", ""active"": true }
]
}";
dynamic data = JObject.Parse(dataJson);
// 动态筛选所有 active 为 true 的 admin 用户
var activeAdmins = data.users
.Where(u => u.role == "admin" && u.active == true);
foreach (var user in activeAdmins)
{
Console.WriteLine($"Name: {user.name}, Role: {user.role}");
}
逻辑分析:
- 使用
dynamic解析 JSON。 - 使用
Where方法筛选符合条件的数据。 - 可以动态组合多个条件,适用于构建通用的数据处理逻辑。
表格总结:dynamic、匿名类型、LINQ to JSON对比
| 特性 | dynamic | 匿名类型 | LINQ to JSON |
|---|---|---|---|
| 类型检查 | 运行时 | 编译时 | 运行时 |
| 是否需要定义类 | 否 | 否 | 否 |
| 适用场景 | 快速解析、临时结构 | 局部绑定、轻量模型 | 数据查询、转换 |
| 可维护性 | 较低 | 中等 | 高 |
| 灵活性 | 高 | 中等 | 高 |
mermaid 流程图:动态解析与数据处理流程
graph TD
A[原始JSON字符串] --> B{解析方式}
B --> C[JObject.Parse + dynamic]
B --> D[JsonConvert.DeserializeAnonymousType]
B --> E[LINQ to JSON 查询]
C --> F[动态访问属性]
D --> G[匿名类型绑定]
E --> H[筛选、排序、投影]
F --> I[输出结果]
G --> I
H --> I
该流程图清晰地展示了三种处理动态JSON数据的方式及其后续处理流程。
本章内容通过丰富的代码示例和详细说明,深入讲解了 Newtonsoft.Json 在处理动态对象和匿名类型方面的强大功能。这些技术在现代C#开发中极为实用,尤其适用于接口解析、快速原型开发、微服务数据交换等场景。下一章将继续探讨枚举类型的序列化处理方式,进一步拓展数据类型的处理能力。
6. 枚举类型的序列化处理
枚举(Enum)类型在C#开发中广泛用于表示一组命名的整数常量。在实际项目中,尤其是在前后端数据交互时,枚举字段的序列化与反序列化处理显得尤为重要。Newtonsoft.Json 提供了灵活的机制来控制枚举值的序列化格式,开发者可以根据业务需求将枚举值序列化为整数、字符串,甚至实现自定义转换逻辑。本章将深入探讨枚举类型在 Newtonsoft.Json 中的序列化与反序列化行为,包括默认行为、字符串转换、大小写兼容性处理以及自定义转换器的实现。
6.1 枚举序列化为字符串与整数
在默认情况下,Newtonsoft.Json 会将枚举值序列化为其底层的整数值。这种行为在某些场景下非常实用,例如数据库映射或需要保持枚举值稳定的系统中。然而,在前后端交互、日志输出等场景中,将枚举值序列化为字符串形式可以提高可读性与可维护性。
6.1.1 默认行为(整数输出)
默认情况下,Newtonsoft.Json 会将枚举值序列化为整数形式。我们可以通过以下示例来验证这一行为:
public enum Status
{
Active = 1,
Inactive = 2,
Pending = 3
}
class Program
{
static void Main()
{
var user = new { Name = "Alice", Status = Status.Pending };
string json = JsonConvert.SerializeObject(user);
Console.WriteLine(json);
}
}
执行结果:
{"Name":"Alice","Status":3}
逻辑分析:
- Status 枚举值 Pending 对应整数 3 。
- JsonConvert.SerializeObject 在未指定任何设置的情况下,默认将枚举值序列化为整数。
- 输出的 JSON 中, Status 字段为整数 3 。
参数说明:
- user 是一个匿名类型,包含 Name 和 Status 字段。
- JsonConvert.SerializeObject 是 Newtonsoft.Json 提供的最基础的序列化方法。
6.1.2 使用 StringEnumConverter 转换为字符串
如果希望将枚举值序列化为字符串形式,可以使用 Newtonsoft.Json 提供的 StringEnumConverter 。该转换器会将枚举值转换为对应的名称字符串。
class Program
{
static void Main()
{
var user = new { Name = "Alice", Status = Status.Pending };
var settings = new JsonSerializerSettings();
settings.Converters.Add(new StringEnumConverter());
string json = JsonConvert.SerializeObject(user, settings);
Console.WriteLine(json);
}
}
执行结果:
{"Name":"Alice","Status":"Pending"}
逻辑分析:
- 通过 JsonSerializerSettings 添加 StringEnumConverter ,告知序列化器将枚举转换为字符串。
- Status.Pending 被序列化为 "Pending" ,提高了 JSON 的可读性。
参数说明:
- JsonSerializerSettings 是控制序列化行为的核心类。
- Converters.Add() 方法用于注册自定义类型转换器。
- StringEnumConverter 是专门用于枚举的字符串转换器。
6.2 枚举反序列化兼容性处理
在反序列化过程中,前端可能传递字符串形式的枚举值,而后端期望的是枚举类型。Newtonsoft.Json 支持将字符串反序列化为对应的枚举值,并且具备一定的容错能力,如忽略大小写和拼写错误。
6.2.1 字符串到枚举的自动映射
下面是一个将 JSON 字符串反序列化为包含枚举字段的对象的示例:
public class User
{
public string Name { get; set; }
public Status Status { get; set; }
}
class Program
{
static void Main()
{
string json = "{\"Name\":\"Bob\",\"Status\":\"Active\"}";
var user = JsonConvert.DeserializeObject<User>(json);
Console.WriteLine(user.Status); // 输出: Active
}
}
逻辑分析:
- JSON 字符串中的 "Status" 字段为 "Active" ,反序列化后被映射为 Status.Active 枚举值。
- 即使未显式注册 StringEnumConverter ,Newtonsoft.Json 默认支持字符串到枚举的映射。
参数说明:
- JsonConvert.DeserializeObject<User> 是将 JSON 字符串反序列化为强类型对象的核心方法。
- User 类包含 Status 枚举字段。
6.2.2 处理大小写与拼写错误
在实际开发中,前端可能传递的枚举字符串存在大小写不一致或轻微拼写错误。Newtonsoft.Json 提供了配置项来增强反序列化的兼容性。
class Program
{
static void Main()
{
string json = "{\"Name\":\"Charlie\",\"Status\":\"acTive\"}";
var settings = new JsonSerializerSettings
{
Converters = { new StringEnumConverter() },
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var user = JsonConvert.DeserializeObject<User>(json, settings);
Console.WriteLine(user.Status); // 输出: Active
}
}
逻辑分析:
- StringEnumConverter 支持大小写不敏感的枚举匹配。
- "acTive" 被成功映射为 Status.Active 。
- CamelCasePropertyNamesContractResolver 用于匹配 JSON 中的字段命名风格(如 camelCase)。
参数说明:
- ContractResolver 控制属性名称的匹配策略。
- StringEnumConverter 在反序列化时也会影响字符串到枚举的映射方式。
6.3 自定义枚举转换逻辑
在某些高级场景中,可能需要为枚举提供更复杂的序列化/反序列化行为,例如多语言支持、别名映射或自定义字符串格式。此时可以通过继承 JsonConverter 实现自定义转换器。
6.3.1 实现自定义 JsonConverter
以下是一个实现自定义枚举转换器的示例,该转换器支持将 Status 枚举转换为中文别名。
public class ChineseEnumConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsEnum;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string enumString = reader.Value.ToString();
switch (enumString)
{
case "活跃": return Status.Active;
case "停用": return Status.Inactive;
case "待定": return Status.Pending;
default: throw new JsonSerializationException($"无法将 {enumString} 映射到枚举值");
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
switch ((Status)value)
{
case Status.Active: writer.WriteValue("活跃"); break;
case Status.Inactive: writer.WriteValue("停用"); break;
case Status.Pending: writer.WriteValue("待定"); break;
}
}
}
使用示例:
class Program
{
static void Main()
{
var user = new { Name = "David", Status = Status.Inactive };
var settings = new JsonSerializerSettings();
settings.Converters.Add(new ChineseEnumConverter());
string json = JsonConvert.SerializeObject(user, settings);
Console.WriteLine(json); // {"Name":"David","Status":"停用"}
string inputJson = "{\"Name\":\"Eve\",\"Status\":\"活跃\"}";
var result = JsonConvert.DeserializeObject<User>(inputJson, settings);
Console.WriteLine(result.Status); // Active
}
}
逻辑分析:
- 自定义 ChineseEnumConverter 实现了 JsonConverter 接口。
- WriteJson 方法控制序列化为中文字符串。
- ReadJson 方法支持将中文字符串反序列化为枚举值。
- 可以支持多语言或别名映射,适用于国际化场景。
参数说明:
- CanConvert 方法判断是否支持当前类型(枚举)。
- WriteJson 和 ReadJson 分别控制序列化与反序列化逻辑。
6.3.2 枚举别名与多语言支持
| 枚举值 | 英文输出 | 中文输出 | 法语输出 |
|---|---|---|---|
| Active | Active | 活跃 | Actif |
| Inactive | Inactive | 停用 | Inactif |
| Pending | Pending | 待定 | En attente |
通过类似 ChineseEnumConverter 的扩展,可以轻松实现多语言输出。例如,使用资源文件( .resx )结合当前线程语言来动态选择输出格式,从而支持多语言系统。
mermaid流程图:
graph TD
A[开始序列化] --> B{是否是枚举类型?}
B -->|是| C[应用自定义转换器]
B -->|否| D[使用默认序列化器]
C --> E[根据当前语言输出对应字符串]
D --> F[输出原始JSON]
总结:
- 枚举的序列化行为可通过 StringEnumConverter 或自定义 JsonConverter 灵活控制。
- 默认情况下,Newtonsoft.Json 将枚举序列化为整数,但可以通过配置转换为字符串。
- 反序列化支持大小写不敏感和基本拼写容错。
- 通过自定义转换器可以实现别名、多语言等复杂需求。
通过本章的学习,开发者可以灵活应对实际项目中枚举字段的序列化与反序列化问题,提升代码的可读性、兼容性与国际化能力。
7. 特殊类型与复杂对象处理
本章将深入探讨 Newtonsoft.Json 在处理 .*** 中特殊类型(如 DateTimeOffset 、 Uri 、 DBNull )以及复杂对象结构(如接口、抽象类、嵌套类)时的行为机制与配置方式。此外,我们还将分析对象图中常见的引用循环问题以及深拷贝对象的处理策略,帮助开发者构建更健壮的 JSON 序列化/反序列化逻辑。
7.1 特殊内置类型的序列化与反序列化
在实际开发中,常常会遇到一些非标准但非常重要的 .*** 内置类型,如 DateTimeOffset 、 Uri 和 DBNull ,这些类型需要特别的处理方式才能确保其在 JSON 中的正确表示和还原。
7.1.1 处理DateTimeOffset与时区信息
DateTimeOffset 类型用于表示带时区偏移的时间值。默认情况下,Newtonsoft.Json 会将其序列化为 ISO 8601 格式字符串,包含完整的时区信息。
var dto = new DateTimeOffset(2025, 4, 5, 10, 30, 0, TimeSpan.FromHours(8));
string json = JsonConvert.SerializeObject(dto);
Console.WriteLine(json); // 输出:"2025-04-05T10:30:00+08:00"
反序列化时,Newtonsoft.Json 会自动识别并还原为 DateTimeOffset 对象:
string json = "\"2025-04-05T10:30:00+08:00\"";
var dto = JsonConvert.DeserializeObject<DateTimeOffset>(json);
Console.WriteLine(dto.Offset); // 输出:+08:00
参数说明 :
-Offset表示当前时间的时区偏移。
- 默认序列化格式为yyyy-MM-ddTHH:mm:ss+zzzz。
如果希望自定义格式,可以通过 JsonSerializerSettings :
var settings = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd HH:mm:ss zzz"
};
string json = JsonConvert.SerializeObject(dto, settings);
7.1.2 Uri、DBNull与DBNull.Value的处理
Uri 类型在 JSON 中通常被序列化为字符串形式:
var uri = new Uri("https://www.example.***");
string json = JsonConvert.SerializeObject(uri);
Console.WriteLine(json); // 输出:"\"https://www.example.***\""
反序列化时需指定泛型类型:
string json = "\"https://www.example.***\"";
var uri = JsonConvert.DeserializeObject<Uri>(json);
Console.WriteLine(uri.Host); // 输出:"www.example.***"
DBNull.Value 是一种特殊类型,常用于数据库交互中表示空值。默认情况下 Newtonsoft.Json 会将其序列化为 null :
object dbNull = DBNull.Value;
string json = JsonConvert.SerializeObject(dbNull);
Console.WriteLine(json); // 输出:null
反序列化时,可以结合 Type.GetType("System.DBNull") 或使用自定义转换器进行处理。
7.2 接口与抽象类的序列化支持
接口和抽象类无法直接实例化,因此在序列化/反序列化过程中需要额外配置来保留类型信息。
7.2.1 TypeNameHandling配置与类型信息保留
默认情况下,Newtonsoft.Json 不会保留类型信息。可以通过设置 TypeNameHandling 来启用类型元数据:
public interface IAnimal
{
string Name { get; }
}
public class Dog : IAnimal
{
public string Name { get; set; }
}
var animal = new Dog { Name = "Buddy" };
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
};
string json = JsonConvert.SerializeObject(animal, settings);
Console.WriteLine(json);
// 输出:{"$type":"YourNamespace.Dog, YourAssembly","Name":"Buddy"}
参数说明 :
-TypeNameHandling.Objects:仅在对象类型上添加$type元数据。
-$type字段用于在反序列化时指定具体类型。
7.2.2 接口对象的序列化与重建
反序列化接口对象时,必须启用 TypeNameHandling 才能还原具体实现类型:
string json = "{\"$type\":\"YourNamespace.Dog, YourAssembly\",\"Name\":\"Buddy\"}";
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
};
var animal = JsonConvert.DeserializeObject<IAnimal>(json, settings);
Console.WriteLine(animal.Name); // 输出:"Buddy"
注意事项 :
- 启用TypeNameHandling可能带来安全风险,建议在受信任的环境中使用。
- 使用Binder可自定义程序集加载逻辑。
7.3 复杂对象的深拷贝与引用处理
当对象之间存在循环引用或嵌套结构时,序列化操作可能会失败或产生冗余数据。Newtonsoft.Json 提供了多种机制来处理这些问题。
7.3.1 引用循环与循环引用处理
以下是一个典型的循环引用结构:
public class Person
{
public string Name { get; set; }
public Person Friend { get; set; }
}
var p1 = new Person { Name = "Alice" };
var p2 = new Person { Name = "Bob" };
p1.Friend = p2;
p2.Friend = p1;
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json); // 输出不包含循环引用部分
选项说明 :
-ReferenceLoopHandling.Ignore:忽略循环引用。
-ReferenceLoopHandling.Serialize:允许序列化并保留引用标记(需启用PreserveReferencesHandling)。
启用引用保留:
var settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
};
string json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json);
// 输出包含 $id 和 $ref 字段
7.3.2 深拷贝对象与对象图还原
利用 Newtonsoft.Json 的序列化/反序列化机制,可以实现对象的深拷贝:
public static T DeepCopy<T>(T obj)
{
string json = JsonConvert.SerializeObject(obj);
return JsonConvert.DeserializeObject<T>(json);
}
var original = new Person { Name = "Alice" };
var copy = DeepCopy(original);
copy.Name = "Bob";
Console.WriteLine(original.Name); // 输出:"Alice"
原理说明 :
- 序列化将对象图转换为字符串。
- 反序列化重新创建对象实例,实现深拷贝。注意 :
- 深拷贝不会保留对象的引用关系,除非启用PreserveReferencesHandling。
- 对于大型对象或嵌套结构,性能需评估。
下一章将介绍 Newtonsoft.Json 的性能优化技巧,包括异步序列化、缓存机制与大数据处理策略。
本文还有配套的精品资源,点击获取
简介:Newtonsoft.Json是C#开发中最流行的JSON处理类库,广泛应用于.***项目中,提供序列化、反序列化、格式化、动态解析等多种功能。该库通过丰富的API和灵活的配置选项,极大提升了处理JSON数据的效率和准确性。本内容通过代码实例详细讲解了其在对象序列化、动态类型解析、枚举处理、格式设置及高级功能中的使用方法,适合C#开发者快速掌握JSON数据的处理技巧,提升项目开发效率。
本文还有配套的精品资源,点击获取