You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:33:11