C#中类反序列化到已有实例及ID与完整对象互转实现
在C#中实现有限项类的Id序列化/反序列化方案
你说的这种场景非常常见——比如国家、城市、货币这类枚举式的有限集合,我们不需要序列化整个对象的所有字段,只需要存它的唯一标识(比如国家Code),反序列化时再根据这个标识从预定义的集合中还原完整对象。下面我用你示例里用到的Newtonsoft.Json(Json.NET)来一步步实现:
第一步:定义实体类与数据源仓库
首先完善你的实体结构,同时创建一个静态仓库类来存储所有有限项的实例(因为是有限列表,提前初始化好所有可能的选项):
// 城市结构体 public struct City { public string Name; // 用自定义转换器处理Country字段的序列化逻辑 [JsonConverter(typeof(CountryIdConverter))] public Country Country; } // 国家类,通过JsonObject特性指定序列化选项 [JsonObject(MemberSerialization.OptIn)] public class Country { // 唯一标识(Id),序列化时仅保留该字段 [JsonProperty] public string Code { get; } [JsonProperty] public string Name { get; } // 私有构造函数,避免外部随意创建实例 private Country(string code, string name) { Code = code; Name = name; } // 静态仓库:存储所有预定义的国家实例 public static class CountryRepository { public static readonly List<Country> AllCountries = new List<Country> { new Country("CN", "China"), new Country("US", "United States"), new Country("JP", "Japan") }; // 根据Code查找对应的国家实例 public static Country GetByCode(string code) { return AllCountries.FirstOrDefault(c => c.Code.Equals(code, StringComparison.OrdinalIgnoreCase)) ?? throw new ArgumentException($"未找到Code为 {code} 的国家"); } } }
第二步:实现自定义Json转换器
核心是编写一个JsonConverter,重写序列化和反序列化的逻辑,实现"对象→Id"和"Id→对象"的转换:
public class CountryIdConverter : JsonConverter<Country> { // 序列化:将Country对象转换为它的Code(Id) public override void WriteJson(JsonWriter writer, Country value, JsonSerializer serializer) { writer.WriteValue(value.Code); } // 反序列化:从Code(Id)还原为完整的Country对象 public override Country ReadJson(JsonReader reader, Type objectType, Country existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.Value is string code) { return Country.CountryRepository.GetByCode(code); } throw new JsonSerializationException($"无效的国家Code:{reader.Value}"); } }
第三步:测试序列化与反序列化
现在验证实际效果:
class Program { static void Main() { // 创建测试用的城市对象 var beijing = new City { Name = "Beijing", Country = Country.CountryRepository.GetByCode("CN") }; // 序列化:输出的JSON中Country字段仅为"CN" string json = JsonConvert.SerializeObject(beijing); Console.WriteLine("序列化结果:"); Console.WriteLine(json); // 输出:{"Name":"Beijing","Country":"CN"} // 反序列化:从JSON还原出包含完整Country信息的City对象 City deserializedCity = JsonConvert.DeserializeObject<City>(json); Console.WriteLine("\n反序列化结果:"); Console.WriteLine($"城市:{deserializedCity.Name},国家:{deserializedCity.Country.Name}(Code:{deserializedCity.Country.Code})"); // 输出:城市:Beijing,国家:China(Code:CN) } }
扩展与注意事项
- 结构体适配:你的City是值类型结构体,转换器依然能正常工作,无需额外调整。
- 异常处理:示例中添加了异常抛出逻辑,实际项目可根据需求改为返回默认值或自定义错误提示。
- 全局注册转换器:如果多个地方需要用到Country的序列化,可不用逐个属性加
[JsonConverter],而是全局注册:var settings = new JsonSerializerSettings(); settings.Converters.Add(new CountryIdConverter()); string json = JsonConvert.SerializeObject(beijing, settings); - 其他序列化库适配:如果使用System.Text.Json,核心思路一致,只需实现
JsonConverter<Country>接口(API细节略有不同)。
内容的提问来源于stack exchange,提问作者Jean
相关产品推荐
相关产品推荐

