如何在.NET System.Text.Json中编写基于属性名的自定义序列化转换器
可行实现方案
JsonConverter<T>的Write方法设计上确实不包含当前序列化属性的元数据,无法直接获取属性名,可通过以下方案实现需求:
方案1:使用JsonTypeInfo修饰器(推荐,适用于.NET 6+)
这是System.Text.Json官方提供的元数据自定义能力,可以在序列化前全局配置所有类型的属性序列化规则,不需要修改业务类代码。
- 先实现两种不同格式的DateTime转换器
// 保留时间部分的转换器 internal class DateTimeWithTimeConverter : JsonConverter<DateTime> { public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return DateTime.Parse(reader.GetString() ?? string.Empty); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); } } // 仅保留日期部分的转换器 internal class DateTimeOnlyDateConverter : JsonConverter<DateTime> { public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return DateTime.Parse(reader.GetString() ?? string.Empty); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString("yyyy-MM-dd")); } }
- 实现全局属性规则匹配逻辑
public static void DateTimeFormatRuleModifier(JsonTypeInfo typeInfo) { // 只处理普通类类型 if (typeInfo.Kind != JsonTypeInfoKind.Object) return; foreach (var property in typeInfo.Properties) { // 只处理DateTime类型的属性 if (property.PropertyType != typeof(DateTime)) continue; // 根据属性名后缀绑定对应转换器 if (property.Name.EndsWith("DateTime", StringComparison.OrdinalIgnoreCase)) { property.CustomConverter = new DateTimeWithTimeConverter(); } else { property.CustomConverter = new DateTimeOnlyDateConverter(); } } }
- 序列化时注入配置
var serializeOptions = new JsonSerializerOptions { TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { DateTimeFormatRuleModifier } } }; // 后续序列化直接使用该options即可 var json = JsonSerializer.Serialize(yourObject, serializeOptions);
方案2:.NET 6以下版本兼容方案
如果使用的是.NET 5及更早版本,没有TypeInfo修饰器能力,可以改用JsonConverterFactory结合特性标记的方式实现:
- 自定义
DateTimeFormatAttribute特性,标记是否保留时间 - 转换器工厂在创建转换器时读取属性上的特性,返回对应格式的转换器
该方案需要给每个DateTime属性加特性,性能和易用性略低于方案1。
效果验证
定义测试类:
public class TestDemo { public DateTime CreateTime { get; set; } = new DateTime(2024,5,20,13,14,15); public DateTime PayDateTime { get; set; } = new DateTime(2024,5,20,13,14,15); }
序列化结果:
{"CreateTime":"2024-05-20","PayDateTime":"2024-05-20 13:14:15"}
内容的提问来源于stack exchange,提问作者zyq
相关产品推荐
相关产品推荐

