JSON序列化问题求助:状态常量包装类序列化难题求解
这种全是魔法字符串的老旧项目维护起来真的闹心,我前阵子刚帮朋友处理过类似的状态管理改造问题!结合你的需求,给你一套分步解决思路,既能实现强类型状态约束,又能搞定JSON序列化的兼容问题:
第一步:定义强类型的状态包装类
首先得把散落在各处的字符串常量封装成一个不可实例化的密封类,确保只有你定义的有效值能被使用,避免随意传无效字符串:
public sealed class Status { // 存储数据库/JSON里的原始字符串值 public string Value { get; } // 预定义的有效状态实例 public static readonly Status Active = new("active"); public static readonly Status Retired = new("retired"); // 私有构造函数,禁止外部随意创建实例 private Status(string value) => Value = value; // 重写Equals和GetHashCode,方便比较状态实例 public override bool Equals(object? obj) => obj is Status status && Value == status.Value; public override int GetHashCode() => Value.GetHashCode(); // 隐式转字符串,兼容原来直接用字符串的场景 public static implicit operator string(Status status) => status.Value; // 显式转Status,从字符串还原成强类型实例 public static explicit operator Status(string value) => value switch { "active" => Active, "retired" => Retired, _ => throw new ArgumentOutOfRangeException(nameof(value), "无效的状态值") }; }
第二步:解决JSON序列化问题
接下来针对你用的JSON库(现在主流是System.Text.Json或Newtonsoft.Json),写自定义转换器,让序列化/反序列化时能在Status实例和字符串之间自动转换:
情况1:使用System.Text.Json(.NET Core/.NET 5+默认)
实现JsonConverter<Status>:
public class StatusJsonConverter : JsonConverter<Status> { public override Status Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); if (value is null) throw new JsonException("状态值不能为空"); return (Status)value; } public override void Write(Utf8JsonWriter writer, Status value, JsonSerializerOptions options) { writer.WriteStringValue(value.Value); } }
然后有两种方式启用转换器:
- 直接在实体类的Status属性上加特性:
public class YourEntity { [JsonConverter(typeof(StatusJsonConverter))] public Status CurrentStatus { get; set; } } - 全局配置(适合大量使用Status的场景):
var serializerOptions = new JsonSerializerOptions(); serializerOptions.Converters.Add(new StatusJsonConverter()); // 序列化示例 var json = JsonSerializer.Serialize(yourEntityInstance, serializerOptions); // 反序列化示例 var entity = JsonSerializer.Deserialize<YourEntity>(json, serializerOptions);
情况2:使用Newtonsoft.Json(Json.NET)
实现JsonConverter<Status>:
public class StatusNewtonsoftConverter : JsonConverter<Status> { public override Status ReadJson(JsonReader reader, Type objectType, Status? existingValue, bool hasExistingValue, JsonSerializer serializer) { var value = reader.Value as string; if (value is null) throw new JsonException("状态值不能为空"); return (Status)value; } public override void WriteJson(JsonWriter writer, Status? value, JsonSerializer serializer) { writer.WriteValue(value?.Value); } }
启用方式同样两种:
- 属性加特性:
public class YourEntity { [JsonConverter(typeof(StatusNewtonsoftConverter))] public Status CurrentStatus { get; set; } } - 全局配置:
var serializerSettings = new JsonSerializerSettings(); serializerSettings.Converters.Add(new StatusNewtonsoftConverter()); var json = JsonConvert.SerializeObject(yourEntityInstance, serializerSettings); var entity = JsonConvert.DeserializeObject<YourEntity>(json, serializerSettings);
额外补充:数据库映射兼容
既然原来数据库存的是字符串,如果你用的是EF Core,还需要加个值转换器让EF能正确映射Status和数据库的字符串类型:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<YourEntity>() .Property(e => e.CurrentStatus) .HasConversion( // 写入数据库时:Status -> 字符串 status => status.Value, // 读取数据库时:字符串 -> Status value => (Status)value); }
这样改造后,既完全杜绝了无效状态值的传入,又能完美兼容原来的JSON序列化和数据库存储逻辑,不用大规模改动现有代码,可以逐步替换原来的魔法字符串,风险很低。
内容的提问来源于stack exchange,提问作者marc_s
相关产品推荐
相关产品推荐

