如何通过特性标记实现UDP二进制数据自动反序列化到自定义模型?
实现方案
1. 自定义特性
首先定义两个特性,分别用于标记字段读取顺序、固定长度数组的长度:
[AttributeUsage(AttributeTargets.Property)] public class BinaryPositionAttribute : Attribute { public int Order { get; } public BinaryPositionAttribute(int order) => Order = order; } [AttributeUsage(AttributeTargets.Property)] public class BinaryArrayLengthAttribute : Attribute { public int Length { get; } public BinaryArrayLengthAttribute(int length) => Length = length; }
2. 定义数据模型
按照你的要求给属性加标记,数组类型额外指定固定长度即可:
public class Model { [BinaryPosition(1)] public byte Field1 { get; set; } [BinaryPosition(2)] public sbyte Field2 { get; set; } [BinaryPosition(3)] [BinaryArrayLength(10)] // 替换为你实际的数组固定长度 public float[] Field3 { get; set; } }
3. 实现通用反序列化器
核心逻辑通过反射读取属性的特性标记,按顺序自动读取对应类型的数据:
public static class BinaryDeserializer { public static T Deserialize<T>(byte[] buffer) where T : new() { var instance = new T(); using var reader = new BinaryReader(new MemoryStream(buffer)); // 按标记的顺序排序所有需要读取的属性 var properties = typeof(T).GetProperties() .Where(p => p.GetCustomAttribute<BinaryPositionAttribute>() != null) .OrderBy(p => p.GetCustomAttribute<BinaryPositionAttribute>().Order) .ToList(); foreach (var prop in properties) { object value; var propType = prop.PropertyType; // 处理固定长度数组 if (propType.IsArray) { var arrayLenAttr = prop.GetCustomAttribute<BinaryArrayLengthAttribute>(); if (arrayLenAttr == null) throw new InvalidOperationException($"数组属性{prop.Name}未指定BinaryArrayLength特性"); var elementType = propType.GetElementType(); var array = Array.CreateInstance(elementType, arrayLenAttr.Length); for (int i = 0; i < arrayLenAttr.Length; i++) { array.SetValue(ReadValueByType(reader, elementType), i); } value = array; } else { value = ReadValueByType(reader, propType); } prop.SetValue(instance, value); } return instance; } // 按类型读取对应值,需要支持更多类型可直接扩展 private static object ReadValueByType(BinaryReader reader, Type type) { if (type == typeof(byte)) return reader.ReadByte(); if (type == typeof(sbyte)) return reader.ReadSByte(); if (type == typeof(float)) return reader.ReadSingle(); if (type == typeof(int)) return reader.ReadInt32(); if (type == typeof(uint)) return reader.ReadUInt32(); if (type == typeof(short)) return reader.ReadInt16(); if (type == typeof(ushort)) return reader.ReadUInt16(); if (type == typeof(long)) return reader.ReadInt64(); if (type == typeof(ulong)) return reader.ReadUInt64(); throw new NotSupportedException($"不支持的类型{type.Name}"); } }
4. 调用方式
和你期望的用法完全一致:
byte[] udpReceivedBuffer = ...; // UDP接收到的原始二进制数据 var model = BinaryDeserializer.Deserialize<Model>(udpReceivedBuffer);
注意事项
- 大小端适配:BinaryReader默认使用小端字节序,若你的UDP协议采用大端字节序,需要修改读取逻辑或提前转换字节序
- 类型扩展:可在
ReadValueByType方法中新增更多类型的读取逻辑,如需支持固定长度字符串可新增BinaryStringLength特性配合使用 - 性能优化:高并发场景下可改用表达式树、源生成技术替代反射实现,进一步降低性能开销,普通业务场景下反射性能完全够用
内容的提问来源于stack exchange,提问作者deha
相关产品推荐
相关产品推荐

