欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > JSON序列化-System.Text.Json

JSON序列化-System.Text.Json

2025/2/24 7:21:15 来源:https://blog.csdn.net/ceclar123/article/details/141296943  浏览:    关键词:JSON序列化-System.Text.Json

JSON序列化-System.Text.Json

  • 序列化
    • 序列化为字符串
    • 序列化为字节数组
    • 中文转码
    • 自定义属性名
      • 1、JsonPropertyName实现
      • 2、JsonSerializerOptions.PropertyNamingPolicy参数
      • 3、自定义命名策略
      • 4、字典key使用命名策略
    • 输出字段顺序控制
    • 枚举展示
    • 属性忽略
      • 1、使用JsonIgnore
      • 2、使用JsonSerializerOptions
    • 包含字段(field)
      • `JsonInclude`
      • `JsonSerializerOptions`的`IncludeFields`字段
    • 格式化输出
    • 日期格式化
  • 反序列化
    • 注意值类型触发异常
      • 示例1
      • 示例2
      • 示例3
    • 必须属性
      • 示例1
      • 示例2
      • 示例3

序列化

序列化为字符串

UserDTO user = new UserDTO
{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true
};
string json = JsonSerializer.Serialize(user);
Console.WriteLine(json);// {"UserName":"\u5F20\u4E09","Age":18,"Birthday":"2000-01-01T01:01:01","IsCheck":true}

输出的中文,竟然被转码了,需要自定义序列化选项来控制输出

序列化为字节数组

UserDTO user = new UserDTO
{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true
};byte[] data = JsonSerializer.SerializeToUtf8Bytes(user);
// 转为字符串
Console.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(data));// {"UserName":"\u5F20\u4E09","Age":18,"Birthday":"2000-01-01T01:01:01","IsCheck":true}

中文转码

设置一下JsonSerializerOptions中的Encoder字段

UserDTO user = new UserDTO
{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true
};JsonSerializerOptions options = new JsonSerializerOptions
{Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
};
string json = JsonSerializer.Serialize(user, options);
Console.WriteLine(json);// {"UserName":"张三","Age":18,"Birthday":"2000-01-01T01:01:01","IsCheck":true}

自定义属性名

1、JsonPropertyName实现

class UserDTO
{[JsonPropertyName("user_name")]public string UserName { get; set; }public int? Age { get; set; }public DateTime? Birthday { get; set; }public bool? IsCheck { get; set; }
}
//
UserDTO user = new UserDTO{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true};string json = JsonSerializer.Serialize(user);Console.WriteLine(json);
// {"user_name":"\u5F20\u4E09","Age":18,"Birthday":"2000-01-01T01:01:01","IsCheck":true}

2、JsonSerializerOptions.PropertyNamingPolicy参数

系统内置了几种名称转换方式(C#默认是大驼峰规则,所以内置策略里面没有这个选项)

微软PropertyNamingPolicy对比

命名策略说明原始属性名称经过转换的属性名称
CamelCase第一个单词以小写字符开头。连续单词以大写字符开头TempCelsiustempCelsius
KebabCaseLower单词由连字符分隔,所有字符均为小写TempCelsiustemp-celsius
KebabCaseUpper单词由连字符分隔,所有字符均为大写TempCelsiusTEMP-CELSIUS
SnakeCaseLower单词用下划线分隔,所有字符均为小写TempCelsiustemp_celsius
SnakeCaseUpper单词用下划线分隔,所有字符均为大写TempCelsiusTEMP_CELSIUS
UserDTO user = new UserDTO
{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true
};JsonSerializerOptions options = new JsonSerializerOptions
{PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};string json = JsonSerializer.Serialize(user, options);
Console.WriteLine(json);// {"user_name":"\u5F20\u4E09","age":18,"birthday":"2000-01-01T01:01:01","is_check":true}

3、自定义命名策略

扩展抽象类JsonNamingPolicy

  • 自定义命名策略

统一在名称前面加前缀

  public class UserNamingPolicy : JsonNamingPolicy{public override string ConvertName(string name){return "ext_" + name;}}
  • 使用自定义命名策略
UserDTO user = new UserDTO
{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true
};JsonSerializerOptions options = new JsonSerializerOptions
{PropertyNamingPolicy = new UserNamingPolicy()
};string json = JsonSerializer.Serialize(user, options);
Console.WriteLine(json);// {"ext_UserName":"\u5F20\u4E09","ext_Age":18,"ext_Birthday":"2000-01-01T01:01:01","ext_IsCheck":true}

4、字典key使用命名策略

字典对象的key是动态的,重命名需要单独设置一下,命名策略是公用的

 class UserDTO{[JsonPropertyName("user_name")]public string UserName { get; set; }public int? Age { get; set; }public DateTime? Birthday { get; set; }public bool? IsCheck { get; set; }public Dictionary<String, object> Ext { get; set; }}///
UserDTO user = new UserDTO{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true,Ext = new Dictionary<string, object> {{ "width", 10 },{ "height", 200 },{ "desc", "测试" }}};JsonSerializerOptions options = new JsonSerializerOptions{//DictionaryKeyPolicy= JsonNamingPolicy.CamelCaseDictionaryKeyPolicy = new UserNamingPolicy()};string json = JsonSerializer.Serialize(user, options);Console.WriteLine(json);// {"user_name":"\u5F20\u4E09","Age":18,"Birthday":"2000-01-01T01:01:01","IsCheck":true,"Ext":{"ext_width":10,"ext_height":200,"ext_desc":"\u6D4B\u8BD5"}}

输出字段顺序控制

通过JsonPropertyOrder来控制,由小到大现实,不设置默认是0

 class UserDTO{[JsonPropertyOrder(100)]public string UserName { get; set; }public int? Age { get; set; }[JsonPropertyOrder(99)]public DateTime? Birthday { get; set; }[JsonPropertyOrder(-100)]public bool? IsCheck { get; set; }[JsonPropertyOrder(-99)]public Dictionary<String, object> Ext { get; set; }}//
UserDTO user = new UserDTO
{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true,Ext = new Dictionary<string, object> {{ "width", 10 },{ "height", 200 },{ "desc", "测试" }}
};JsonSerializerOptions options = new JsonSerializerOptions
{//DictionaryKeyPolicy= JsonNamingPolicy.CamelCaseDictionaryKeyPolicy = new UserNamingPolicy()
};string json = JsonSerializer.Serialize(user, options);
Console.WriteLine(json);// {"IsCheck":true,"Ext":{"ext_width":10,"ext_height":200,"ext_desc":"\u6D4B\u8BD5"},"Age":18,"Birthday":"2000-01-01T01:01:01","UserName":"\u5F20\u4E09"}

枚举展示

默认情况下,枚举会序列化为数字(默认从0开始,也可以自定义)。 若要将枚举名称序列化为字符串,需要使用JsonStringEnumConverter,设置JsonSerializerOptions类的Converters字段
JsonStringEnumConverter有两个关键参数
1、namingPolicy,输出的字符串可以配置命名策略,默认为null,原样输出
2、allowIntegerValues,默认为true,当为true时,如果枚举值未定义,它将以数字形式输出,而不是字符串形式
-定义Gender枚举

  public enum Gender{Male, Female}
  • 定义UserDTO
 class UserDTO{[JsonPropertyOrder(100)]public string UserName { get; set; }public int? Age { get; set; }[JsonPropertyOrder(99)]public DateTime? Birthday { get; set; }[JsonPropertyOrder(-100)]public bool? IsCheck { get; set; }[JsonPropertyOrder(-99)]public Dictionary<String, object> Ext { get; set; }public Gender? UserGender { get; set; }}
  • 使用枚举
UserDTO user = new UserDTO
{UserName = "张三",Age = 18,Birthday = new DateTime(2000, 1, 1, 1, 1, 1),IsCheck = true,Ext = new Dictionary<string, object> {{ "width", 10 },{ "height", 200 },{ "desc", "测试" }},UserGender = Gender.Male
};JsonSerializerOptions options = new JsonSerializerOptions
{Converters =    {new JsonStringEnumConverter()}
};string json = JsonSerializer.Serialize(user, options);
Console.WriteLine(json);// {"IsCheck":true,"Ext":{"width":10,"height":200,"desc":"\u6D4B\u8BD5"},"Age":18,"UserGender":"Male","Birthday":"2000-01-01T01:01:01","UserName":"\u5F20\u4E09"}

属性忽略

默认情况下,所有公共属性都会序列化。 如果不想让某些属性出,可以使用如下方法控制输出

1、使用JsonIgnore

主要针对单个属性,个性化配置

  • Never,序列化、反序列化
  • Always,永远会被忽略
  • WhenWritingDefault,默认值场景,会被忽略(例如引用类型时的null)
  • WhenWritingNull,适用引用类型,为null时被忽略
  • 定义UserDTO
 class UserDTO{[JsonIgnore(Condition = JsonIgnoreCondition.Always)]public string UserName { get; set; }[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]public int Age { get; set; }[JsonIgnore(Condition = JsonIgnoreCondition.Never)]public DateTime? Birthday { get; set; }[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]public bool? IsCheck { get; set; }public Dictionary<String, object> Ext { get; set; }public Gender? UserGender { get; set; }}
  • 具体使用
 UserDTO user = new UserDTO{UserName = "张三",Age = 0,UserGender = Gender.Male};JsonSerializerOptions options = new JsonSerializerOptions{Converters =    {new JsonStringEnumConverter()}};string json = JsonSerializer.Serialize(user, options);Console.WriteLine(json);// {"Birthday":null,"Ext":null,"UserGender":"Male"}

UserName : 设置为Always,永不显示,无论是否有值
Birthday:设置为Never,永远显示,为null也会显示
Age:设置为WhenWritingDefault,默认值不显示,值类型,默认为0,所以不显示
IsCheck:设置为WhenWritingNull,null不显示,可空类型,默认为null

2、使用JsonSerializerOptions

  • IgnoreReadOnlyProperties忽略所有只读属性
JsonSerializerOptionsoptions = new JsonSerializerOptions
{IgnoreReadOnlyProperties = true
};
  • DefaultIgnoreCondition,与JsonIgnore的条件通用
JsonSerializerOptions options = new JsonSerializerOptions
{DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
  • 定义UserDTO
 class UserDTO{public string UserName { get; set; }public int Age { get; set; }public DateTime? Birthday { get; private set; } = new DateTime(2000, 12, 20, 1, 1, 1);public bool? IsCheck { get; set; }public Dictionary<String, object> Ext { get; set; }public Gender? UserGender { get; set; }}
  • 使用
 UserDTO user = new UserDTO{UserName = "张三",};JsonSerializerOptions options = new JsonSerializerOptions{IgnoreReadOnlyProperties = true,DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull};string json = JsonSerializer.Serialize(user, options);Console.WriteLine(json);
// {"UserName":"\u5F20\u4E09","Age":0}

Birthday:set方法是私有的,属于只读属性,虽然有值,但是也会被忽略
Ext :引用类型,null,被忽略

包含字段(field)

一般情况,公共属性字段默认会被序列化,但是字段(field)默认不会被序列化,如果需要把指定的field序列化,需要特殊设置

JsonInclude

针对单个field进行设置

 [JsonInclude]public String Hello;

JsonSerializerOptionsIncludeFields字段

全局field设置

JsonSerializerOptions options = new JsonSerializerOptions
{IncludeFields = true
};
  • 定义UserDTO
   class UserDTO{public string UserName { get; set; }[JsonInclude]public String Hello;public String World;}
  • 使用
UserDTO user = new UserDTO
{UserName = "张三",Hello = "hello",World = "world"
};JsonSerializerOptions options = new JsonSerializerOptions
{IncludeFields = true
};string json = JsonSerializer.Serialize(user, options );
Console.WriteLine(json);

格式化输出

JsonSerializerOptions类的WriteIndented字段

   UserDTO user = new UserDTO{UserName = "张三",Birthday = new DateTime(2000, 12, 20, 1, 1, 1)};JsonSerializerOptions options = new JsonSerializerOptions{WriteIndented = true,DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull};string json = JsonSerializer.Serialize(user, options);Console.WriteLine(json);
{"UserName": "\u5F20\u4E09","Age": 0,"Birthday": "2000-12-20T01:01:01"
}

日期格式化

需要扩展JsonConverter抽象类,实现自定义类型转换输出

  • 定义日期转换器
  public class DateTimJsonConverter : JsonConverter<DateTime>{public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){return DateTime.Parse(reader.GetString());}public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options){writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));}}
  • 使用
UserDTO user = new UserDTO
{UserName = "张三",Birthday = new DateTime(2000, 12, 20, 1, 1, 1)
};JsonSerializerOptions options = new JsonSerializerOptions
{DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,Converters = {new DateTimJsonConverter()}
};string json = JsonSerializer.Serialize(user, options);
Console.WriteLine(json);// {"UserName":"\u5F20\u4E09","Age":0,"Birthday":"2000-12-20 01:01:01"}

反序列化

注意值类型触发异常

  • 对于值类型属性,例如int等,json文本中该属性最好有合法的值,否则整个key-value数据就不要提供,否则会抛异常
  • 将值类型定义为可空类型,例如int换成int?或则Nullable<int> (不确定上游系统返回的数据格式,尽量做好兼容)
 class UserDTO{public string UserName { get; set; }public int Age { get; set; }public DateTime? Birthday { get; set; }public bool? IsCheck { get; set; }public Dictionary<String, object> Ext { get; set; }public Gender? UserGender { get; set; }}

示例1

这里是一个正常返回的示例,Age虽然是值类型,但是提供的数据,有正常的值

string json = """{"UserName":"张三","Age":18,"IsCheck":true,"Birthday":"2000-12-20T01:01:01"}""";
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);

示例2

这里没有提供Age数据,反序列化不会解析这个字段,会给默认值0

string json = """{"UserName":"张三","IsCheck":true,"Birthday":"2000-12-20T01:01:01"}""";
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);

示例3

这里给值类型的Age提供了null,肯定会抛异常;类似场景在Java中有intInteger
如果Age属性定义为int?,就当成引用类型处理,最终解析为null

string json = """{"UserName":"张三","Age":null,"IsCheck":true,"Birthday":"2000-12-20T01:01:01"}""";
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);

必须属性

必须的要求哪怕提供null也是可以的,否则验证不通过

  • required关键字
  • JsonRequiredAttribute属性
  • JsonSerializerOptionsTypeInfoResolver字段
class UserDTO
{public required string UserName { get; set; }[JsonRequired]public Nullable<int> Age { get; set; }public DateTime? Birthday { get; set; }public bool? IsCheck { get; set; }public Dictionary<String, object> Ext { get; set; }public Gender? UserGender { get; set; }
}

示例1

Age字段标记必须,提供一个null也代表赋值了,可以通过验证

string json = """{"UserName":"张三","Age":null,"IsCheck":true,"Birthday":"2000-12-20T01:01:01"}""";
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);

示例2

UserName字段标记必须,输入数据没提供任何数据,验证不通过

string json = """{"Age":null,"IsCheck":true,"Birthday":"2000-12-20T01:01:01"}""";
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);

示例3

通过TypeInfoResolver设置某个属性是否必须

JsonSerializerOptions options = new JsonSerializerOptions{TypeInfoResolver = new DefaultJsonTypeInfoResolver{Modifiers ={static typeInfo =>{if (typeInfo.Kind != JsonTypeInfoKind.Object){return;}foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties){if("UserName".Equals(propertyInfo.Name)){propertyInfo.IsRequired = true;}}}}}};string json = """{"Age":null,"IsCheck":true,"Birthday":"2000-12-20T01:01:01"}""";UserDTO user = JsonSerializer.Deserialize<UserDTO>(json, options);

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词