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

.NET中如何将自定义对象序列化为原始类型

Question

我现在有一堆原本是简单整数的ID,为了获得编译器的类型检查支持,我把它们封装成了强类型的结构体,代码如下:

public struct CustomId { 
    private readonly int id; 
    public CustomId(int id) => this.id = id; 
    public static implicit operator int(CustomId cid) => cid.id; 
    public static implicit operator CustomId(int id) => new CustomId(id); 
}

这个结构体本质就是带特定名称的int,我希望在序列化的时候能直接输出成int类型(比如JSON里Person对象的Id字段直接显示为42而不是嵌套的对象)。目前我已经给Newtonsoft JSON写了自定义的JsonConverter并且能用,但想找一个更通用的方案——比如实现System.Runtime.Serialization命名空间下的特性或接口,让多数序列化框架(JSON、XML、Protobuf等)都能兼容,不用为每种框架单独写转换器。有没有这样的方案?


Answer

好问题!确实有几个通用的方案能让你的强类型ID在多数序列化框架下自动被当作基础int处理,不用逐个适配:

1. 实现 ISerializable 接口(通用序列化契约)

System.Runtime.Serialization.ISerializable 是.NET原生的通用序列化接口,很多框架(包括BinaryFormatter、XML Serializer,甚至部分主流JSON库)都会识别它。你只需要在结构体里实现这个接口,指定序列化时只输出内部的int值:

using System.Runtime.Serialization;

public struct CustomId : ISerializable
{
    private readonly int id;
    public CustomId(int id) => this.id = id;

    // 保留原有的隐式转换逻辑
    public static implicit operator int(CustomId cid) => cid.id;
    public static implicit operator CustomId(int id) => new CustomId(id);

    // ISerializable 核心实现:定义序列化时输出的内容
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        // 直接把内部int值作为当前对象的序列化内容
        info.AddValue("value", id);
    }

    // 必须的反序列化构造函数,否则框架无法还原对象
    private CustomId(SerializationInfo info, StreamingContext context)
    {
        id = info.GetInt32("value");
    }
}

这个方案的优势是通用性极强,只要序列化框架兼容ISerializable,就能自动完成CustomId和int的序列化/反序列化转换。

2. 使用 DataContract 和 DataMember 特性

如果你的序列化框架支持WCF数据契约规范(比如DataContractSerializer、Newtonsoft JSON、Protobuf-net等),可以用[DataContract]和[DataMember]特性简化配置,让框架直接序列化内部的int字段:

using System.Runtime.Serialization;

[DataContract]
public struct CustomId
{
    // 标记内部int字段为序列化成员,可自定义名称适配业务场景
    [DataMember(Name = "Id")]
    private readonly int id;
    public CustomId(int id) => this.id = id;

    // 保留隐式转换逻辑
    public static implicit operator int(CustomId cid) => cid.id;
    public static implicit operator CustomId(int id) => new CustomId(id);
}

这个写法更简洁,而且多数现代序列化框架对DataContract特性有原生支持,包括XML序列化、JSON序列化,甚至Protobuf-net也能通过配置快速识别。

3. 添加 TypeConverter 适配.NET类型系统

你还可以给CustomId添加一个TypeConverter,让.NET类型系统自动识别它和int的转换关系,这样不仅序列化框架能受益,其他.NET组件(比如UI控件、配置系统)也能自动处理类型转换:

using System.ComponentModel;

[TypeConverter(typeof(CustomIdConverter))]
public struct CustomId
{
    private readonly int id;
    public CustomId(int id) => this.id = id;

    // 保留隐式转换逻辑
    public static implicit operator int(CustomId cid) => cid.id;
    public static implicit operator CustomId(int id) => new CustomId(id);

    // 自定义类型转换器
    private class CustomIdConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(int) || base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is int intValue)
                return new CustomId(intValue);
            return base.ConvertFrom(context, culture, value);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(int) || base.CanConvertTo(context, destinationType);
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(int) && value is CustomId customId)
                return customId.id;
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }
}

额外小技巧(.NET 6+)

如果你用的是.NET 6及以上版本,可以用record struct简化强类型ID的写法,同时结合上面的方案,代码会更简洁:

[DataContract]
public record struct CustomId([property: DataMember] int Value)
{
    public static implicit operator int(CustomId cid) => cid.Value;
    public static implicit operator CustomId(int id) => new(id);
}

内容的提问来源于stack exchange,提问作者Emil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:24:23