如何使用 System.Text.Json 自定义属性名称和值
默认情况下,属性名称和字典键在 JSON 输出中保持不变,包括大小写。 枚举值表示为数字。 属性按定义的顺序进行序列化。 但是,可以通过以下方法自定义这些行为:
- 指定特定的序列化属性名称。
- 使用内置命名策略(如 camelCase、snake_case 或 kebab-case)作为属性名称和字典键。
- 对属性名称和字典键使用自定义命名策略。
- 使用或不使用命名策略序列化枚举值作为字符串。
- 配置序列化属性的顺序。
注意
Web 默认命名策略为 camel case。
提示
可以使用 AI 帮助以使用 GitHub Copilot 自定义属性名称和值。
对于需要对 JSON 属性名称和值进行特殊处理的其他方案,可以实现自定义转换器。
自定义单个属性名称
若要设置单个属性的名称,请使用 [JsonPropertyName] 特性。
下面是要进行序列化的示例类型和生成的 JSON:
public class WeatherForecastWithPropertyName
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
[JsonPropertyName("Wind")]
public int WindSpeed { get; set; }
}
Public Class WeatherForecastWithPropertyName
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
<JsonPropertyName("Wind")>
Public Property WindSpeed As Integer
End Class
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot",
"Wind": 35
}
此特性设置的属性名称:
- 同时适用于两个方向(序列化和反序列化)。
- 优先于属性命名策略。
- 不影响参数化构造函数的参数名称匹配。
使用内置命名策略
下表显示了内置命名策略以及它们如何影响属性名称。
命名策略 | 说明 | 原始属性名称 | 经过转换的属性名称 |
---|---|---|---|
CamelCase | 第一个单词以小写字符开头。 连续单词以大写字符开头。 |
TempCelsius |
tempCelsius |
KebabCaseLower* | 单词由连字符分隔。 所有字符均为小写。 |
TempCelsius |
temp-celsius |
KebabCaseUpper* | 单词由连字符分隔。 所有字符均为大写。 |
TempCelsius |
TEMP-CELSIUS |
SnakeCaseLower* | 单词用下划线分隔。 所有字符均为小写。 |
TempCelsius |
temp_celsius |
SnakeCaseUpper* | 单词用下划线分隔。 所有字符均为大写。 |
TempCelsius |
TEMP_CELSIUS |
* 在 .NET 8 及更高版本中可用。
以下示例演示如何通过将 JsonSerializerOptions.PropertyNamingPolicy 设置为 JsonNamingPolicy.CamelCase,对所有 JSON 属性名称使用 camel case:
var serializeOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
Dim serializeOptions As JsonSerializerOptions = New JsonSerializerOptions With {
.PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions)
下面是要进行序列化的示例类和 JSON 输出:
public class WeatherForecastWithPropertyName
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
[JsonPropertyName("Wind")]
public int WindSpeed { get; set; }
}
Public Class WeatherForecastWithPropertyName
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
<JsonPropertyName("Wind")>
Public Property WindSpeed As Integer
End Class
{
"date": "2019-08-01T00:00:00-07:00",
"temperatureCelsius": 25,
"summary": "Hot",
"Wind": 35
}
命名策略:
- 适用于序列化和反序列化。
- 由
[JsonPropertyName]
特性替代。 这便是示例中的 JSON 属性名称Wind
不是 camel 大小写的原因。
注意
内置命名策略都不支持代理项对的字母。 有关详细信息,请参阅 dotnet/runtime 问题 90352。
使用自定义 JSON 属性命名策略
若要使用自定义 JSON 属性命名策略,请创建派生自 JsonNamingPolicy 的类,并替代 ConvertName 方法,如下面的示例中所示:
using System.Text.Json;
namespace SystemTextJsonSamples
{
public class UpperCaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name) =>
name.ToUpper();
}
}
Imports System.Text.Json
Namespace SystemTextJsonSamples
Public Class UpperCaseNamingPolicy
Inherits JsonNamingPolicy
Public Overrides Function ConvertName(name As String) As String
Return name.ToUpper()
End Function
End Class
End Namespace
然后,将 JsonSerializerOptions.PropertyNamingPolicy 属性设置为命名策略类的实例:
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = new UpperCaseNamingPolicy(),
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);
Dim options As JsonSerializerOptions = New JsonSerializerOptions With {
.PropertyNamingPolicy = New UpperCaseNamingPolicy,
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast1, options)
下面是要进行序列化的示例类和 JSON 输出:
public class WeatherForecastWithPropertyName
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
[JsonPropertyName("Wind")]
public int WindSpeed { get; set; }
}
Public Class WeatherForecastWithPropertyName
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
<JsonPropertyName("Wind")>
Public Property WindSpeed As Integer
End Class
{
"DATE": "2019-08-01T00:00:00-07:00",
"TEMPERATURECELSIUS": 25,
"SUMMARY": "Hot",
"Wind": 35
}
JSON 属性命名策略:
- 适用于序列化和反序列化。
- 由
[JsonPropertyName]
特性替代。 这便是示例中的 JSON 属性名称Wind
不是大写的原因。
对字典键使用命名策略
如果要序列化的对象的属性的类型为 Dictionary<string,TValue>
,则可以使用命名策略(如 camel case)转换 string
键。 为此,请将 JsonSerializerOptions.DictionaryKeyPolicy 设置为所需的命名策略。 以下示例使用 CamelCase
命名策略:
var options = new JsonSerializerOptions
{
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);
Dim options As JsonSerializerOptions = New JsonSerializerOptions With {
.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast, options)
使用名为 TemperatureRanges
且具有键值对 "ColdMinTemp", 20
和 "HotMinTemp", 40
的字典序列化对象会产生类似于以下示例的 JSON 输出:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot",
"TemperatureRanges": {
"coldMinTemp": 20,
"hotMinTemp": 40
}
}
字典键的命名策略仅适用于序列化。 如果反序列化字典,即使将 JsonSerializerOptions.DictionaryKeyPolicy 设置为非默认命名策略,这些键也会与 JSON 文件匹配。
作为字符串的枚举
默认情况下,枚举会序列化为数字。 若要将枚举名称序列化为字符串,请使用 JsonStringEnumConverter 或 JsonStringEnumConverter<TEnum> 转换器。 Native AOT 运行时仅支持 JsonStringEnumConverter<TEnum>。
默认情况下,枚举会序列化为数字。 若要将枚举名称序列化为字符串,请使用 JsonStringEnumConverter 转换器。
例如,假设需要序列化以下具有枚举的类:
public class WeatherForecastWithEnum
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public Summary? Summary { get; set; }
}
public enum Summary
{
Cold, Cool, Warm, Hot
}
Public Class WeatherForecastWithEnum
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As Summary
End Class
Public Enum Summary
Cold
Cool
Warm
Hot
End Enum
如果 Summary 为 Hot
,则默认情况下序列化的 JSON 具有数值 3:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": 3
}
下面的示例代码序列化枚举名称(而不是数值),并将名称转换为 camel 大小写:
options = new JsonSerializerOptions
{
WriteIndented = true,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);
options = New JsonSerializerOptions With {
.WriteIndented = True
}
options.Converters.Add(New JsonStringEnumConverter(JsonNamingPolicy.CamelCase))
jsonString = JsonSerializer.Serialize(weatherForecast, options)
生成的 JSON 类似于以下示例:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "hot"
}
内置 JsonStringEnumConverter 还可以反序列化字符串值。 无论有没有指定的命名策略,它都能正常工作。 下面的示例演示如何使用 CamelCase
进行反序列化:
options = new JsonSerializerOptions
{
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithEnum>(jsonString, options)!;
options = New JsonSerializerOptions
options.Converters.Add(New JsonStringEnumConverter(JsonNamingPolicy.CamelCase))
weatherForecast = JsonSerializer.Deserialize(Of WeatherForecastWithEnum)(jsonString, options)
还可以通过用 JsonConverterAttribute 批注枚举来指定要使用的转换器。 以下示例演示如何使用 JsonConverterAttribute 属性来指定 JsonStringEnumConverter<TEnum>(.NET 8 和更高版本中可用)。 例如,假设需要序列化以下具有枚举的类:
public class WeatherForecastWithPrecipEnum
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public Precipitation? Precipitation { get; set; }
}
[JsonConverter(typeof(JsonStringEnumConverter<Precipitation>))]
public enum Precipitation
{
Drizzle, Rain, Sleet, Hail, Snow
}
以下示例代码序列化枚举名称,而不是数值:
var options = new JsonSerializerOptions
{
WriteIndented = true,
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);
生成的 JSON 类似于以下示例:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Precipitation": "Sleet"
}
若要将转换器用于源生成,请参阅将枚举字段序列化为字符串。
配置序列化属性的顺序
默认情况下,属性按在类中定义的顺序进行序列化。 通过 [JsonPropertyOrder]
特性,可指定序列化的 JSON 输出中的属性顺序。 Order
属性的默认值是零。 如果将 Order
设置为正数,则会将属性放置在具有默认值的属性后面。 如果 Order
是负数,则会将属性放置在具有默认值的属性前面。 属性按 Order
值从小到大的顺序编写的。 下面是一个示例:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace PropertyOrder
{
public class WeatherForecast
{
[JsonPropertyOrder(-5)]
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
[JsonPropertyOrder(-2)]
public int TemperatureF { get; set; }
[JsonPropertyOrder(5)]
public string? Summary { get; set; }
[JsonPropertyOrder(2)]
public int WindSpeed { get; set; }
}
public class Program
{
public static void Main()
{
var weatherForecast = new WeatherForecast
{
Date = DateTime.Parse("2019-08-01"),
TemperatureC = 25,
TemperatureF = 25,
Summary = "Hot",
WindSpeed = 10
};
var options = new JsonSerializerOptions { WriteIndented = true };
string jsonString = JsonSerializer.Serialize(weatherForecast, options);
Console.WriteLine(jsonString);
}
}
}
// output:
//{
// "Date": "2019-08-01T00:00:00",
// "TemperatureF": 25,
// "TemperatureC": 25,
// "WindSpeed": 10,
// "Summary": "Hot"
//}
使用 Github Copilot 自定义属性名称和顺序
你可以在 IDE 中使用 GitHub Copilot 生成代码来自定义序列化属性的名称和顺序。
如果你使用的是 Visual Studio 2022 版本 17.8 或更高版本,则可以尝试在 Visual Studio 中使用 AI 驱动的 GitHub Copilot 来生成代码,此代码使用 System.Text.Json
自定义属性名称和序列化的 JSON 输出中的顺序。 在 Copilot Chat 窗口中以提示形式提交问题,如以下示例所示。 还可以在编辑器窗口中使用内联聊天提交提示。
注意
GitHub Copilot 由 AI 提供支持,因此可能会带来意外和错误。 请确保验证任何生成的代码或建议。 有关 GitHub Copilot 的常规用途、产品影响、人工监督和隐私的更多信息,请参阅 GitHub Copilot 常见问题解答。
以下示例演示如何使用 Copilot 修改现有代码,以在序列化为 JSON 时自定义属性名称和顺序。
在编辑器中将以下 C# 示例代码添加到
Example.cs
代码文件中。 在 Visual Studio 中,你可以使用 C# 控制台应用程序项目来试用此示例。using System.Text.Json; public class Person { public string? FirstName { get; set; } public string? LastName { get; set; } public int Age { get; set; } public string? Country { get; set; } } public class Program { public static void Main() { var person = new Person { FirstName = "John", LastName = "Doe", Age = 30, Country = "USA" }; string jsonString = JsonSerializer.Serialize(person); Console.WriteLine(jsonString); } }
Example.cs
代码执行以下操作:- 创建
Person
类的实例,并使用值初始化其属性。 - 使用
JsonSerializer.Serialize
. 将person
对象序列化为 JSON 字符串。 - 将以下 JSON 字符串打印到控制台:
{"FirstName":"John","LastName":"Doe","Age":30,"Country":"USA"}
- 创建
在 Copilot Chat 中,输入以下提示以修改代码来自定义 JSON 序列化输出的名称和顺序。
#Example.cs
修改代码以使用System.Text.Json
自定义序列化中 JSON 输出的属性名称和顺序。 设置属性名称:将 FirstName 设置为 first_name,将 LastName 设置为 last_name。 将顺序设置为:Country、FirstName、LastName、Age。 提供自定义的序列化输出。提示符中的
#Example.cs
向 Copilot 提供文件引用作为上下文。 可以自定义提示以输出 JSON 字符串与符合要求的属性名称和值。 要设置意向,并通过已限定范围上下文获取更好的答案,你可以使用聊天功能(如斜杠命令、引用文件、方法或类和线程)。以下输出显示了 Copilot 聊天响应示例:
To customize the property names and order of the JSON output using System.Text.Json, you can use the JsonPropertyName attribute to rename properties and the JsonPropertyOrder attribute to set the order. Here's how you can modify your code: using System.Text.Json; using System.Text.Json.Serialization; public class Person { [JsonPropertyName("first_name")] [JsonPropertyOrder(2)] public string? FirstName { get; set; } [JsonPropertyName("last_name")] [JsonPropertyOrder(3)] public string? LastName { get; set; } [JsonPropertyOrder(4)] public int Age { get; set; } [JsonPropertyOrder(1)] public string? Country { get; set; } } public class Program { public static void Main() { var person = new Person { FirstName = "John", LastName = "Doe", Age = 30, Country = "USA" }; string jsonString = JsonSerializer.Serialize(person, new JsonSerializerOptions { WriteIndented = true }); Console.WriteLine(jsonString); } } **Explanation:** 1. Renaming Properties: The JsonPropertyName attribute is used to rename FirstName to first_name and LastName to last_name. 2. Ordering Properties: The JsonPropertyOrder attribute is used to set the order of the properties in the JSON output. The order is set as: • Country (Order 1) • FirstName (Order 2) • LastName (Order 3) • Age (Order 4) 3. Indented JSON: The JsonSerializerOptions with WriteIndented = true is used to make the JSON output more readable. **Customized Serialization Output:** { "Country": "USA", "first_name": "John", "last_name": "Doe", "Age": 30 } This ensures that the JSON output has the customized property names and the specified order.
当 Copilot 返回代码块时,响应包括用于复制代码、将代码插入新文件或预览代码输出的选项。
注意
结果可能与示例响应中显示的结果不同。 AI 模型不确定,这意味着当被问及相同的问题时,它们可以返回不同的响应。 这可能是由于一段时间内进行的额外学习和调整、语言变体、上下文中的更改(如聊天历史记录等)。