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

如何通过特性标记实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 09:27:02