【C# 序列化】序列化选项 JsonSerializerOptions 类
内容来源:https://docs.microsoft.com/zh-cn/dotnet/api/system.text.json.jsonproperty?view=net-6.0
命名空间System.Text.Json
JsonSerializerOptions 类
序列化选项用于控制要对象的序列化的或这Json 字符的反序列化,
构造函数
内容来源:如何使用 System.Text.Json 实例化 JsonSerializerOptions 实例
JsonSerializerOptions() :初始化JsonSerializerOptions类的一个新实例。
JsonSerializerOptions(JsonSerializerDefaults) :用由指定的JsonSerializerDefaults确定的预定义选项集构造一个新的枚举 JsonSerializerOptions实例。
JsonSerializerOptions(JsonSerializerOptions) :将选项从JsonSerializerOptions实例复制到一个新实例。
构造函数的使用
1、重用JsonSerializerOptions实例
如果你使用相同的选项重复使用JsonSerializerOptions,不要每次使用时都创建一个新的JsonSerializerOptions实例。为每个调用重用相同的实例。此指导适用于为自定义转换器编写的代码和调用JsonSerializer时。序列化或JsonSerializer.Deserialize。跨多个线程使用相同的实例是安全的。选项实例上的元数据缓存是线程安全的,并且该实例在第一次序列化或反序列化之后是不可变的。
下面的代码演示了使用新选项实例的性能损失。
JsonSerializerOptions(JsonSerializerDefaults)案例如下:
using System.Diagnostics; using System.Text.Json; namespace OptionsPerfDemo { public record Forecast(DateTime Date, int TemperatureC, string Summary); public class Program { public static void Main() { Forecast forecast = new(DateTime.Now, 40, "Hot"); JsonSerializerOptions options = new() { WriteIndented = true }; int iterations = 100000; var watch = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) { Serialize(forecast, options); } watch.Stop(); Console.WriteLine($"Elapsed time using one options instance: {watch.ElapsedMilliseconds}"); watch = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) { Serialize(forecast); } watch.Stop(); Console.WriteLine($"Elapsed time creating new options instances: {watch.ElapsedMilliseconds}"); } private static void Serialize(Forecast forecast, JsonSerializerOptions? options = null) { _ = JsonSerializer.Serialize<Forecast>( forecast, options ?? new JsonSerializerOptions() { WriteIndented = true }); } } } // Produces output like the following example: // //Elapsed time using one options instance: 190 //Elapsed time creating new options instances: 40140
2、JsonSerializerOptions的Web默认值为JsonSerializerDefaults.Web
JsonSerializerDefaults.Web
枚举项目包含以下:
- PropertyNameCaseInsensitive =
true
- JsonNamingPolicy = CamelCase
- NumberHandling = AllowReadingFromString
有一个JsonSerializerOptions构造函数,它允许您用ASP的默认选项创建一个新实例。NET Core用于web应用程序,如下例所示:
using System.Text.Json; namespace OptionsDefaults { public class Forecast { public DateTime? Date { get; init; } public int TemperatureC { get; set; } public string? Summary { get; set; } }; public class Program { public static void Main() { Forecast forecast = new() { Date = DateTime.Now, TemperatureC = 40, Summary = "Hot" }; JsonSerializerOptions options = new(JsonSerializerDefaults.Web) { WriteIndented = true }; Console.WriteLine( $"PropertyNameCaseInsensitive: {options.PropertyNameCaseInsensitive}"); Console.WriteLine( $"JsonNamingPolicy: {options.PropertyNamingPolicy}"); Console.WriteLine( $"NumberHandling: {options.NumberHandling}"); string forecastJson = JsonSerializer.Serialize<Forecast>(forecast, options); Console.WriteLine($"Output JSON:\n{forecastJson}"); Forecast? forecastDeserialized = JsonSerializer.Deserialize<Forecast>(forecastJson, options); Console.WriteLine($"Date: {forecastDeserialized?.Date}"); Console.WriteLine($"TemperatureC: {forecastDeserialized?.TemperatureC}"); Console.WriteLine($"Summary: {forecastDeserialized?.Summary}"); } } } // Produces output like the following example: // //PropertyNameCaseInsensitive: True //JsonNamingPolicy: System.Text.Json.JsonCamelCaseNamingPolicy //NumberHandling: AllowReadingFromString //Output JSON: //{ // "date": "2020-10-21T15:40:06.9040831-07:00", // "temperatureC": 40, // "summary": "Hot" //} //Date: 10 / 21 / 2020 3:40:06 PM //TemperatureC: 40 //Summary: Hot
3、复制JsonSerializerOptions
JsonSerializerOptions(JsonSerializerOptions) :将选项从JsonSerializerOptions实例复制到一个新实例。案例如下:
using System.Text.Json; namespace CopyOptions { public class Forecast { public DateTime Date { get; init; } public int TemperatureC { get; set; } public string? Summary { get; set; } }; public class Program { public static void Main() { Forecast forecast = new() { Date = DateTime.Now, TemperatureC = 40, Summary = "Hot" }; JsonSerializerOptions options = new() { WriteIndented = true }; JsonSerializerOptions optionsCopy = new(options); string forecastJson = JsonSerializer.Serialize<Forecast>(forecast, optionsCopy); Console.WriteLine($"Output JSON:\n{forecastJson}"); } } } // Produces output like the following example: // //Output JSON: //{ // "Date": "2020-10-21T15:40:06.8998502-07:00", // "TemperatureC": 40, // "Summary": "Hot" //}
属性:
记忆方法:4个Hand(枚举处理、数组处理) 、3个Ignore、Json属性命名策略 3(属性名命名规则、字典key做Json属性命名规则、师傅) 其他。
- AllowTrailingCommas 允许尾部的逗号 获取或设置一个值,该值指示在被反序列化的JSON有效负载中,是否允许(或忽略)在对象或数组中的JSON值列表的末尾添加额外的逗号。
- Converters 变换器 获取已注册的用户定义转换器的列表。
- DefaultBufferSize 默认缓冲区大小 获取或设置创建临时缓冲区时要使用的默认缓冲区大小(以字节为单位)。
- DefaultIgnoreCondition 忽略所有默认值属性 获取或设置一个值,该值确定在序列化或反序列化期间何时忽略具有默认值的属性。缺省值为“Never”。用到JsonIgnoreCondition枚举
- DictionaryKeyPolicy 字典Key的命名规则 获取或设置用于将IDictionary键名转换为另一种格式(如驼色大小写)的策略。
- Encoder 编码器 获取或设置转义字符串时要使用的编码器,或为空以使用默认编码器。https://www.cnblogs.com/cdaniu/p/16024229.html
- IgnoreNullValues 忽略 NullValues 过时了。获取或设置一个值,该值指示在序列化和反序列化期间是否忽略空值。缺省值为false。
- IgnoreReadOnlyFields 忽略只读字段 获取或设置一个值,该值指示在序列化期间是否忽略只读字段。如果一个字段被标记为readonly关键字,那么它就是只读的。缺省值为false。
- IgnoreReadOnlyProperties 忽略只读取属性 获取一个值,该值指示在序列化期间是否忽略只读属性。缺省值为false。
- IncludeFields 是否序列化字段 获取或设置一个值,该值指示是否在序列化和反序列化期间处理字段。缺省值为false, 设置位true后,就可以序列化属性和字段。。
- MaxDepth 最大深度 获取或设置序列化或反序列化JSON时允许的最大深度,默认值0表示最大深度为64。一个对象(或数组)A{}的深度为0,对象(或数组)中嵌套对象或数组A{B[]} 深度为1 以此类推
- NumberHandling 数字的序列化/反序列化方式 获取或设置一个对象,该对象指定在序列化或反序列化时应如何处理数字类型,此属性是在序列化或反序列化发生后设置的。用到JsonNumberHandling 位枚举
- PropertyNameCaseInsensitive 反序列化期间属性名称大小写不区分 获取或设置一个值,该值指示属性的名称在反序列化期间是否使用不区分大小写的比较。缺省值为false 区分大小写。用到JsonSerializerDefaults 枚举
- PropertyNamingPolicy 命名规则 获取或设置一个值,该值指定用于将对象上的属性名称转换为另一种格式(例如驼峰大小写)或为空以保持属性名称不变的策略。
- ReadCommentHandling 阅读注释处理 获取或设置一个值,该值定义在反序列化期间如何处理注释, 用到
JsonCommentHandling枚举
。 - ReferenceHandler 引用处理程序 获取或设置一个对象,该对象指定在读取和写入JSON时如何处理对象引用 用到 ReferenceHandler 类。
- UnknownTypeHandling 未知类型处理 获取或设置一个对象,该对象指定在反序列化期间如何处理声明为object的类型的反序列化。
- WriteIndented 按格式输出 获取或设置一个值,该值指示JSON是否应该使用格式化打印。默认情况下false,JSON序列化时没有任何额外的空格。
2、Converters :【C# 序列化】 自定义Json转换器模式
详细请查看:https://www.cnblogs.com/cdaniu/p/15968261.html
4、忽略所有默认值属性/或字段
设置该属性,需要JsonIgnoreCondition枚举。若要防止对值类型属性中的默认值进行序列化,请将 DefaultIgnoreCondition 属性设置为JsonIgnoreCondition.WhenWritingDefault,如以下示例中所示:
相当于
[JsonIgnore(Condition =JsonIgnoreCondition.WhenWritingDefault)] public string Name3 = default;//将被忽略,因为使用默认值
MySerializeable serializeable = new (); var serializeOption = new JsonSerializerOptions() { AllowTrailingCommas=false, WriteIndented=true, DefaultIgnoreCondition=JsonIgnoreCondition.WhenWritingDefault,//忽略默认的属性或字段 IncludeFields=true,//开启忽略字段,默认情况下是false }; string jsonString = JsonSerializer.Serialize(serializeable,serializeOption); writer.WriteLine(jsonString); writer.Close(); public class MySerializeable { public int Name4 ;//会被忽略因为是默认值 }
5、字典Key序列化的命名规则
如果要序列化的对象的属性为 Dictionary<string,TValue>
类型,则 string
键可转换为 camel 大小写。 为此,请将 DictionaryKeyPolicy 设置为 JsonNamingPolicy.CamelCase
,如下面的示例中所示:
MySerializeable serializeable = new() ; serializeable.Lictionaryy.Add("XiaoMi","26"); serializeable.Lictionaryy.Add("LuaWei", "26"); var serializeOption = new JsonSerializerOptions() { WriteIndented = true, DictionaryKeyPolicy =JsonNamingPolicy.CamelCase, }; string jsonString = JsonSerializer.Serialize<MySerializeable>(serializeable,serializeOption); var desr=JsonSerializer.Deserialize<MySerializeable>(jsonString,serializeOption);//反序列化时候要使用序列化配置 Console.WriteLine(jsonString); Console.Read(); public class MySerializeable { public double FloatNumberOne { get; set; } public int NumberTwo { get; set; } public Dictionary<string,string> Lictionaryy { get; set; }=new Dictionary<string,string>(); } /*{ "FloatNumberOne": "NaN", "NumberTwo": 123, "Lictionaryy": { "xiaoMi": "26", "luaWei": "26" } }*/
6、Encoder
//保证中文字符正确显示。CjkUnifiedIdeographs 象行文字 代表中文(Chinese)、日文(Japanese )、韩文(Korean)的字符集合 JsonSerializerOptions jso = new JsonSerializerOptions { Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs),//从拉丁文字到象行文字 }; public class Myserliazer { [JsonInclude] public string Name = "哈哈" }
8条和9条 IgnoreReadOnlyFields和IgnoreReadOnlyProperties
忽略大小
StreamWriter writer = GetCurrentStream(); MySerializeable serializeable = new (); var serializeOption = new JsonSerializerOptions() { AllowTrailingCommas=false, WriteIndented=true, IgnoreReadOnlyFields=true, //忽略只读字段 IgnoreReadOnlyProperties=false, //默认false }; string jsonString = JsonSerializer.Serialize(serializeable,serializeOption); writer.WriteLine(jsonString); writer.Close(); StreamWriter GetCurrentStream() { Environment.CurrentDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); string fullName = Directory.CreateDirectory("Test").FullName; StreamWriter streamWriter = File.CreateText(Path.Combine(fullName, "text.txt")); return streamWriter; } public class MySerializeable { public readonly string Name = "dfdf"; public readonly int[] Info= { 10, 20, 30 }; public string Description { private set; get; } } /*输出 * { "Description": null, "Info": [ 10, 20, 30 ] }*/
10条和18条IncludeFields和WriteIndented
StreamWriter writer = GetCurrentStream(); MySerializeable serializeable = new (); var serializeOption = new JsonSerializerOptions() { AllowTrailingCommas=false, IncludeFields = true,//包含字段,默认只包含属性,设置位true后,就可以序列化属性和字段。 WriteIndented=true,//格式化输出 }; string jsonString = JsonSerializer.Serialize(serializeable,serializeOption); writer.WriteLine(jsonString); writer.Close(); StreamWriter GetCurrentStream() { Environment.CurrentDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); string fullName = Directory.CreateDirectory("Test").FullName; StreamWriter streamWriter = File.CreateText(Path.Combine(fullName, "text.txt")); return streamWriter; } public class MySerializeable { public string Name = "dfdf"; public int[] Info= { 10, 20, 30 }; } /*输出 * { "Name": "dfdf", "Info": [ 10, 20, 30 ] }*/
11、MaxDepth
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using GongHuiNewtonsoft.Json; using GongHuiNewtonsoft.Json.Serialization; using GongHuiNewtonsoft.Json.Converters; namespace JSONDemo { class Program { static void Main(string[] args) { try { JsonConvert.DeserializeObject<List<IList<IList<string>>>>(@"[ [ [ '3', 'Three', 'III' ] ] ]", new JsonSerializerSettings { MaxDepth = 2 //MaxDepth=3 }); } catch (JsonReaderException ex) { Console.WriteLine(ex.Message); } } } }
12、序列化/反序列化数字解析方式
在设置JsonNumberHandling选项时用到JsonSerializerDefaults 位枚举
序列化和反序列化时数字的保存和解析方法
【AllowNamedFloatingPointLiterals 模式】不是标准的json格式,“NaN”、“Infinity”和“-Infinity”字符串标记可以被读为浮点常量,这些常量的Single和Double值将被写为它们对应的JSON字符串表示。
【Strict 反序列化模式】数字将只从数字标记读取,将只被写入JSON数字("Number":123,)。
【AllowReadingFromString 反序列化模式】可以从String令牌中读取数字。不阻止从Number令牌读取数字。Number":"123"
【WriteAsString 序列化模式】不是标准的json格式,序列化时将数字写成字符串的形式。
使用案例:
MySerializeable serializeable = new() ; serializeable.FloatNumberOne = double.NaN;//序列化时候,需要将 NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,否会出错 serializeable.NumberTwo = 123; var serializeOption = new JsonSerializerOptions() { WriteIndented = true, NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals| JsonNumberHandling.AllowReadingFromString| JsonNumberHandling.WriteAsString, }; string jsonString = JsonSerializer.Serialize<MySerializeable>(serializeable,serializeOption); var desr=JsonSerializer.Deserialize<MySerializeable>(jsonString,serializeOption);//反序列化时候要使用序列化配置,不配置会报错 Console.WriteLine(jsonString); public class MySerializeable { public double FloatNumberOne { get; set; } public int NumberTwo { get; set; } }
13、反序列化时不区分属性大小写
默认情况下,反序列化会查找 JSON 与目标对象属性之间区分大小写的属性名称匹配。 若要更改该行为,请将 JsonSerializerOptions.PropertyNameCaseInsensitive 设置为 true
:
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, options); public class WeatherForecast { public DateTimeOffset Date { get; set; } public int TemperatureCelsius { get; set; } public string? Summary { get; set; } } /*{ "date": "2019-08-01T00:00:00-07:00", "temperatureCelsius": 25, "summary": "Hot", } */
14、PropertyNamingPolicy 命名规则
该选项用到JsonNamingPolicy 类,可以继承该类重写ConvertName()方法自定义命名规则
MySerializeable serializeable = new() ; serializeable.FloatNumberOne = double.NaN;//序列化时候,需要将 NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals serializeable.NumberTwo = 123; var serializeOption = new JsonSerializerOptions() { WriteIndented = true, NumberHandling=JsonNumberHandling.AllowNamedFloatingPointLiterals, PropertyNamingPolicy =JsonNamingPolicy.CamelCase, }; string jsonString = JsonSerializer.Serialize<MySerializeable>(serializeable,serializeOption); var desr=JsonSerializer.Deserialize<MySerializeable>(jsonString,serializeOption);//反序列化时候要使用序列化配置 Console.WriteLine(jsonString); Console.Read(); public class MySerializeable { public double FloatNumberOne { get; set; } public int NumberTwo { get; set; } } /*{ "floatNumberOne": "NaN", "numberTwo": 123 }*/
自定义命名规则。
MySerializeable serializeable = new() ; serializeable.FloatNumberOne = double.NaN;//序列化时候,需要将 NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals serializeable.NumberTwo = 123; var serializeOption = new JsonSerializerOptions() { WriteIndented = true, NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, PropertyNamingPolicy = new ToUpper(), }; string jsonString = JsonSerializer.Serialize<MySerializeable>(serializeable,serializeOption); var desr=JsonSerializer.Deserialize<MySerializeable>(jsonString,serializeOption);//反序列化时候要使用序列化配置 Console.WriteLine(jsonString); Console.Read(); public class ToUpper : JsonNamingPolicy { public override string ConvertName(string name) => name.ToUpper(); } public class MySerializeable { public double FloatNumberOne { get; set; } public int NumberTwo { get; set; } } /*{ "FLOATNUMBERONE": "NaN", "NUMBERTWO": 123 }*/
15、允许注释
默认情况下,JSON 中不允许使用注释和尾随逗号。 若要在 JSON 中允许注释,请将 JsonSerializerOptions.ReadCommentHandling 属性设置为 JsonCommentHandling.Skip
。
var options = new JsonSerializerOptions { ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true, }; var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, options)!;
下面是包含注释和尾随逗号的示例 JSON:
{ "Date": "2019-08-01T00:00:00-07:00", "TemperatureCelsius": 25, // Fahrenheit 77 "Summary": "Hot", /* Zharko */ // Comments on /* separate lines */ }
IJsonOnDeserializing, IJsonOnDeserialized, IJsonOnSerializing, IJsonOnSerialized
public class Serializeables : IJsonOnDeserializing, IJsonOnDeserialized,IJsonOnSerializing, IJsonOnSerialized { public bool[] Serbool = { true, true, true }; public void OnSerializing() => Console.WriteLine("序列化中"); public void OnDeserializing() => Console.WriteLine("反序列化中"); public void OnDeserialized() => Console.WriteLine("反序列化后"); public void OnSerialized() => Console.WriteLine("序列化后"); }
特性