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

基于特性的C#自定义数据通用序列化器开发问询

基于特性的C#自定义数据通用序列化器开发问询

看起来你已经迈出了关键第一步——定义好JSON格式对应的实体类,现在想要打造一个通用序列化器,既能支持JSON、MessagePack这类不同格式的序列化/反序列化,还能严格遵循预设的数据结构规范对吧?我来给你梳理一套可行的实现思路,结合特性标记来约束格式,同时保证整体的通用性。

你已实现的JSON实体类示例

[Serializable]
public class JsonDataset
{
    [JsonProperty("frames")]
    public List<JsonHandFrame> Frames { get; set; }
}

[Serializable]
public class JsonHandFrame
{
    [JsonProperty("leftHand")]
    public JsonHand LeftHand { get; set; }
    [JsonProperty("rightHand")]
    public JsonHand RightHand { get; set; }
}

[Serializable]
public class JsonHand
{
    [JsonProperty("joints")]
    public JsonJoint[] Joints { get; set; }
}

[Serializable]
public class JsonJoint
{
    [JsonProperty("x")]
    public float JsonX { get; set; }
    [JsonProperty("y")]
    public float JsonY { get; set; }
    [JsonProperty("z")]
    public float JsonZ { get; set; }
}

(推测你对应的MessagePack实体类会使用[MessagePackObject]、[Key]这类特性,结构和JSON实体类一致)


第一步:抽象序列化接口,统一契约

先定义一个通用接口,让不同格式的序列化器都遵循这个标准,上层调用时就不用关心具体是哪种序列化实现:

public interface ISerializer<T>
{
    // 字符串形式的序列化/反序列化(适合JSON)
    string Serialize(T data);
    T Deserialize(string serializedData);
    
    // 字节数组形式的序列化/反序列化(适合MessagePack这类二进制格式)
    byte[] SerializeToBytes(T data);
    T DeserializeFromBytes(byte[] bytes);
}

第二步:用自定义特性统一字段映射(可选但推荐)

如果不想让实体类绑定到特定序列化库的特性,可以自定义一个通用字段映射特性,后续在具体序列化器中解析这个特性来匹配字段名:

[AttributeUsage(AttributeTargets.Property)]
public class DataFieldAttribute : Attribute
{
    public string FieldName { get; }
    public DataFieldAttribute(string fieldName)
    {
        FieldName = fieldName;
    }
}

修改实体类,用自定义特性替换或补充原有库特性:

[Serializable]
public class JsonDataset
{
    [DataField("frames")]
    [JsonProperty("frames")] // 暂时保留原有特性,后续可通过自定义解析器替换
    public List<JsonHandFrame> Frames { get; set; }
}
// 其他实体类同理修改

第三步:实现具体格式的序列化器

针对JSON和MessagePack分别实现上面的接口,利用成熟的第三方库简化开发:

JSON序列化器(基于Newtonsoft.Json)

public class JsonSerializer<T> : ISerializer<T>
{
    private readonly Newtonsoft.Json.JsonSerializer _innerSerializer;

    public JsonSerializer()
    {
        _innerSerializer = new Newtonsoft.Json.JsonSerializer
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Formatting = Formatting.Indented
            // 如果用自定义DataField特性,可以在这里实现自定义ContractResolver来映射字段名
        };
    }

    public string Serialize(T data)
    {
        using var sw = new StringWriter();
        _innerSerializer.Serialize(sw, data);
        return sw.ToString();
    }

    public T Deserialize(string serializedData)
    {
        using var sr = new StringReader(serializedData);
        return _innerSerializer.Deserialize<T>(new JsonTextReader(sr));
    }

    public byte[] SerializeToBytes(T data)
    {
        var jsonStr = Serialize(data);
        return Encoding.UTF8.GetBytes(jsonStr);
    }

    public T DeserializeFromBytes(byte[] bytes)
    {
        var jsonStr = Encoding.UTF8.GetString(bytes);
        return Deserialize(jsonStr);
    }
}

MessagePack序列化器(基于MessagePack-CSharp)

public class MessagePackSerializer<T> : ISerializer<T>
{
    public string Serialize(T data)
    {
        var bytes = SerializeToBytes(data);
        return Convert.ToBase64String(bytes);
    }

    public T Deserialize(string serializedData)
    {
        var bytes = Convert.FromBase64String(serializedData);
        return DeserializeFromBytes(bytes);
    }

    public byte[] SerializeToBytes(T data)
    {
        return global::MessagePack.MessagePackSerializer.Serialize(data);
    }

    public T DeserializeFromBytes(byte[] bytes)
    {
        return global::MessagePack.MessagePackSerializer.Deserialize<T>(bytes);
    }
}

第四步:封装工厂类,简化调用

为了更方便地切换序列化器,可以写一个工厂类,根据类型返回对应的实现:

public static class SerializerFactory
{
    public static ISerializer<T> GetSerializer<T>(SerializerType type)
    {
        return type switch
        {
            SerializerType.Json => new JsonSerializer<T>(),
            SerializerType.MessagePack => new MessagePackSerializer<T>(),
            _ => throw new ArgumentOutOfRangeException(nameof(type), "不支持的序列化类型")
        };
    }
}

public enum SerializerType
{
    Json,
    MessagePack
}

调用示例

// 构造测试数据
var testDataset = new JsonDataset
{
    Frames = new List<JsonHandFrame>
    {
        new JsonHandFrame
        {
            LeftHand = new JsonHand
            {
                Joints = new[]
                {
                    new JsonJoint { JsonX = 0.1f, JsonY = 0.2f, JsonZ = 0.3f }
                }
            }
        }
    }
};

// JSON序列化/反序列化
var jsonSerializer = SerializerFactory.GetSerializer<JsonDataset>(SerializerType.Json);
string jsonResult = jsonSerializer.Serialize(testDataset);
var deserializedJson = jsonSerializer.Deserialize(jsonResult);

// MessagePack序列化/反序列化
var msgPackSerializer = SerializerFactory.GetSerializer<JsonDataset>(SerializerType.MessagePack);
byte[] msgPackBytes = msgPackSerializer.SerializeToBytes(testDataset);
var deserializedMsgPack = msgPackSerializer.DeserializeFromBytes(msgPackBytes);

额外优化建议

  • 可以在序列化/反序列化前后添加格式校验逻辑,比如检查必填字段是否存在、数据类型是否符合要求,保证输出严格遵循规范。
  • 针对自定义DataField特性,实现对应的契约解析器,让序列化库自动识别字段映射,避免实体类上重复标记多个库的特性。
  • 把序列化器的配置(比如JSON的格式化选项、MessagePack的压缩策略)抽离成独立配置类,增强灵活性。

备注:内容来源于stack exchange,提问作者Gytis Dokšas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 07:03:04