Json序列化是项目开发中非常常见的需求
(现在那么多的API靠Json传递参数之类的)
而C#对Json序列化/反序列化的支持也是非常完善的
下面讲几个我在项目中使用到的技巧
需要注意的是,下面的代码均使用.net9以上,老版本的.net可能还不支持相关功能
Json序列化/反序列化主要通过添加Attribute或者设置option实现
<0x01> 通过Attribute可以实现的
属性值重命名
一般情况下,Json序列化/反系列化基于属性名
大部分情况下也没啥问题
但有时,Json属性名会和C#关键字冲突
比方这个Json
{
"object": "list",
"data": [
{
"id": "deepseek-chat",
"object": "model",
"owned_by": "deepseek"
},
{
"id": "deepseek-reasoner",
"object": "model",
"owned_by": "deepseek"
}
]
}
(Deepseek获取模型的json示例)
这时候就必须重命名了
可以通过JsonPropertyName特性给属性重命名,匹配Json的名字
public class ModelsObject
{
[JsonPropertyName("object")]
public string ObjectType { get; set; }
public ModelData[] data { get; set; }
public class ModelData
{
public string id { get; set; }
[JsonPropertyName("object")]
public string ObjectType { get; set; }
public string owned_by { get; set; }
}
}
这里就给object这个属性做了重命名
通常Json都是下划线命名,C#属性通常大驼峰命名
所以我基本上是都做重命名的
枚举重命名
跟上面差不多,Json的命名习惯跟C#有差异
我也习惯自己做一遍重命名
需要使用JsonStringEnumMemberName特性
public enum EnumTest
{
[JsonStringEnumMemberName("enum_a")]
AAA,
[JsonStringEnumMemberName("enum_b")]
BBB,
}
是否包含某属性
一般情况下C#的序列化会去序列化public属性,不序列化private/protected属性
这个是可以控制的,通过标记JsonInclude特性或者JsonIgnore特性
public class TestObject
{
// 这个属性按默认是会被序列化的,但这里指定忽略
[JsonIgnore]
public string PropertyA { get; set; }
// 这个属性默认是不会被序列化的,但这里指定包含
[JsonInclude]
private string PropertyB { get; set; }
}
多态类型的序列化
有些时候,会需要传一个List,List里面有不同类型的数据
理想的情况就是List指定基类类型,里面存放派生类型
这时候要给这个List做序列化,需要用JsonDerivedType特性做下派生类型标记
不然只会序列化基类的属性,即使List中的对象是多态的
var objectList = new List<ObjectBase>();
// 假设随便塞了点数据
var jsonString = JsonSerializer.Serialize(objectList);
[JsonDerivedType(typeof(ObjectA))]
[JsonDerivedType(typeof(ObjectB))]
public class ObjectBase
{
public string Name { get; set; }
}
public class ObjectA : ObjectBase
{
public int IntProperty { get; set; }
}
public class ObjectB : ObjectBase
{
public float FloatProperty { get; set; }
}
<0x02> 通过option可以实现的
这里的option指的是JsonSerializerOptions类型对象
可以在序列化时传入的参数
比如这样
var option = new JsonSerializerOptions()
{
//...
}
var jsonString = JsonSerializer.Serialize(obj, option);
忽略/包括空值属性
C#在处理空值时,默认会带上这个属性,输出为null
可以设置成如果是空值,就忽略这个属性
需要通过设置DefaultIgnoreCondition
比如说
// 当属性值为空时忽略这个属性输出
var option = new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
}
JsonIgnoreCondition有下面的值
- Never
- 总是序列化/反序列化,并且无视IgnoreNullValues的设置
- Always
- 总是忽略
- WhenWritingDefault
- 当属性值等于默认值时忽略
- WhenWritingNull
- 当属性值为null时忽略
- 只有类型为引用类型时有效
从枚举中转换
很多时候,Json传递的string值是固定的几个选项
这时候,在C#中选择枚举是非常合适的
需要在设置中指定Converters
比如这样
// 这样指定即可
var option = new JsonSerializerOptions()
{
Converters = { new JsonStringEnumConverter() },
}