JSON(JavaScript Object Notation)已成为现代Web应用和API开发中最常用的数据交换格式。C#提供了多种处理JSON的方式,从基础的字符串操作到强大的序列化库。本文将介绍如何在C#中优雅高效地处理JSON数据。
一、.NET中的JSON处理基础
1.1 JSON基础知识回顾
JSON由以下几种基本结构组成:
- 键值对集合(对象):
{"name": "John", "age": 30}
- 值的有序列表(数组):
[1, 2, 3, 4, 5]
- 基本数据类型:字符串、数字、布尔值、null
1.2 .NET中的JSON处理方式
.NET提供了多种处理JSON的方式:
System.Text.Json
- .NET Core 3.0+引入的高性能JSON库Newtonsoft.Json
(Json.NET) - 最流行的第三方JSON库
二、使用System.Text.Json处理JSON
System.Text.Json
是.NET Core 3.0及更高版本中的内置JSON库,性能优异且无需额外依赖。
2.1 基本序列化与反序列化
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime BirthDate { get; set; }
}
class Program
{
static void Main()
{
// 创建对象
var person = new Person
{
Name = "张三",
Age = 30,
BirthDate = new DateTime(1990, 1, 1)
};
// 序列化为JSON字符串
string jsonString = JsonSerializer.Serialize(person);
Console.WriteLine(jsonString);
// 反序列化JSON字符串为对象
var deserializedPerson = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
}
}
2.2 自定义序列化选项
// 配置序列化选项
var options = new JsonSerializerOptions
{
WriteIndented = true, // 美化输出
PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // 属性名使用驼峰命名
Converters = { new DateTimeConverterUsingDateTimeParse() } // 自定义转换器
};
// 使用配置的选项进行序列化
string jsonString = JsonSerializer.Serialize(person, options);
2.3 处理复杂类型
public class Company
{
public string Name { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
}
// 序列化复杂对象
var company = new Company
{
Name = "微软",
Employees = new List<Employee>
{
new Employee { Name = "张三", Salary = 50000 },
new Employee { Name = "李四", Salary = 60000 }
}
};
string companyJson = JsonSerializer.Serialize(company, options);
Console.WriteLine(companyJson);
// 反序列化复杂对象
var deserializedCompany = JsonSerializer.Deserialize<Company>(companyJson);
三、使用Newtonsoft.Json(Json.NET)处理JSON
Newtonsoft.Json是.NET生态中最流行的JSON库,功能强大且灵活。
3.1 安装Newtonsoft.Json
通过NuGet安装:
Install-Package Newtonsoft.Json
3.2 基本序列化与反序列化
using Newtonsoft.Json;
// 序列化
string jsonString = JsonConvert.SerializeObject(person);
Console.WriteLine(jsonString);
// 反序列化
var deserializedPerson = JsonConvert.DeserializeObject<Person>(jsonString);
Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
3.3 高级特性
3.3.1 自定义转换器
public class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return DateTime.ParseExact(reader.Value.ToString(), "yyyy-MM-dd", CultureInfo.InvariantCulture);
}
public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString("yyyy-MM-dd"));
}
}
// 使用自定义转换器
var settings = new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new DateTimeConverter() }
};
string jsonString = JsonConvert.SerializeObject(person, settings);
3.3.2 处理动态JSON
// 动态解析JSON
string dynamicJson = @"{""name"":""张三"",""age"":30}";
dynamic personDynamic = JsonConvert.DeserializeObject<dynamic>(dynamicJson);
Console.WriteLine($"Name: {personDynamic.name}, Age: {personDynamic.age}");
// 使用JObject
JObject jObject = JObject.Parse(dynamicJson);
string name = (string)jObject["name"];
int age = (int)jObject["age"];
3.3.3 处理JSON数组
string jsonArray = @"[
{""name"":""张三"",""age"":30},
{""name"":""李四"",""age"":25}
]";
List<Person> people = JsonConvert.DeserializeObject<List<Person>>(jsonArray);
foreach (var person in people)
{
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
四、性能优化技巧
4.1 选择合适的库
- System.Text.Json:性能最佳,适合高性能场景
- Newtonsoft.Json:功能最丰富,适合复杂场景
4.2 重用序列化设置
// 创建一次并重用
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
// 使用时直接传入
string jsonString = JsonSerializer.Serialize(person, _jsonOptions);
4.3 流式处理大JSON
对于大JSON文件,使用流式API避免内存问题:
// 使用System.Text.Json流式读取
using (FileStream fs = File.OpenRead("large.json"))
using (JsonDocument doc = JsonDocument.Parse(fs))
{
JsonElement root = doc.RootElement;
// 处理JSON数据
}
// 使用Newtonsoft.Json流式读取
using (StreamReader sr = new StreamReader("large.json"))
using (JsonTextReader reader = new JsonTextReader(sr))
{
while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject)
{
// 处理对象
}
}
}
4.4 避免频繁分配
// 不好的做法 - 每次创建新选项
for (int i = 0; i < 1000; i++)
{
var options = new JsonSerializerOptions();
JsonSerializer.Serialize(person, options);
}
// 好的做法 - 重用选项
var options = new JsonSerializerOptions();
for (int i = 0; i < 1000; i++)
{
JsonSerializer.Serialize(person, options);
}
五、实际应用示例
5.1 API响应处理
// 使用System.Text.Json处理API响应
public async Task<User> GetUserAsync(int userId)
{
using HttpClient client = new HttpClient();
string url = $"https://api.example.com/users/{userId}";
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string jsonString = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<User>(jsonString, _jsonOptions);
}
// 使用Newtonsoft.Json处理API响应
public async Task<User> GetUserAsync(int userId)
{
using HttpClient client = new HttpClient();
string url = $"https://api.example.com/users/{userId}";
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<User>(jsonString, _settings);
}
5.2 配置文件处理
// 读取JSON配置文件
public class AppConfig
{
public string ConnectionString { get; set; }
public int Timeout { get; set; }
public List<string> AllowedOrigins { get; set; }
}
public AppConfig LoadConfig(string path)
{
string json = File.ReadAllText(path);
return JsonSerializer.Deserialize<AppConfig>(json, _jsonOptions);
// 或使用Newtonsoft.Json: return JsonConvert.DeserializeObject<AppConfig>(json, _settings);
}
// 保存JSON配置文件
public void SaveConfig(AppConfig config, string path)
{
string json = JsonSerializer.Serialize(config, _jsonOptions);
File.WriteAllText(path, json);
// 或使用Newtonsoft.Json: File.WriteAllText(path, JsonConvert.SerializeObject(config, _settings));
}
5.3 动态数据交换
// 处理动态JSON数据
public void ProcessDynamicData(string json)
{
// 使用System.Text.Json
JsonDocument doc = JsonDocument.Parse(json);
JsonElement root = doc.RootElement;
if (root.TryGetProperty("name", out JsonElement nameElement))
{
string name = nameElement.GetString();
// 处理name
}
// 使用Newtonsoft.Json
dynamic data = JsonConvert.DeserializeObject<dynamic>(json);
string name = data.name;
// 处理name
}
-
选择合适的库:
- 新项目优先使用
System.Text.Json
- 需要高级功能或迁移现有代码使用
Newtonsoft.Json
- 新项目优先使用
-
性能优化:
- 重用序列化设置
- 对于大JSON使用流式API
- 避免不必要的分配
-
错误处理:
- 总是处理可能的JSON解析异常
- 验证输入JSON的结构
-
代码组织:
- 为复杂类型创建专门的DTO(数据传输对象)
- 使用自定义转换器处理特殊格式
-
安全性:
- 反序列化时验证数据
- 限制最大JSON大小防止DoS攻击