基于特性的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
相关产品推荐
相关产品推荐

