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

C#利用目标类反射读取非Windows设备生成的二进制文件问题求助

解决方案

你遇到的报错本质是BinaryReader.ReadBytes()返回的是byte[]类型,无法直接赋值给非字节数组的其他值类型字段,同时原有的数组赋值逻辑也无法适配非byte[]的数组类型(比如float[,]这类C风格二维数组)。以下方案可实现无分支、无unsafe、无需频繁修改结构体定义的通用解析:

1. 封装通用字节转值类型方法

支持基础值类型、枚举、自定义结构体,同时兼容跨设备字节序差异:

// 通用字节数组转目标类型方法,isLittleEndian参数根据非Windows设备实际字节序设置
private static object ConvertFromBytes(byte[] buffer, Type targetType, bool isLittleEndian = false)
{
    // 字节序适配:设备字节序与当前系统不一致时反转字节
    if (BitConverter.IsLittleEndian != isLittleEndian)
    {
        Array.Reverse(buffer);
    }
    
    TypeCode typeCode = Type.GetTypeCode(targetType);
    return typeCode switch
    {
        TypeCode.Boolean => BitConverter.ToBoolean(buffer, 0),
        TypeCode.Char => BitConverter.ToChar(buffer, 0),
        TypeCode.SByte => (sbyte)buffer[0],
        TypeCode.Byte => buffer[0],
        TypeCode.Int16 => BitConverter.ToInt16(buffer, 0),
        TypeCode.UInt16 => BitConverter.ToUInt16(buffer, 0),
        TypeCode.Int32 => BitConverter.ToInt32(buffer, 0),
        TypeCode.UInt32 => BitConverter.ToUInt32(buffer, 0),
        TypeCode.Int64 => BitConverter.ToInt64(buffer, 0),
        TypeCode.UInt64 => BitConverter.ToUInt64(buffer, 0),
        TypeCode.Single => BitConverter.ToSingle(buffer, 0),
        TypeCode.Double => BitConverter.ToDouble(buffer, 0),
        // 自动处理枚举类型
        _ when targetType.IsEnum => Enum.ToObject(targetType, ConvertFromBytes(buffer, Enum.GetUnderlyingType(targetType), isLittleEndian)),
        // 自动处理自定义结构体,无需提前定义Marshal特性
        _ => Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0), targetType)
    };
}

2. 封装多维数组转换方法

无需unsafe代码即可支持C风格二维/多维数组解析:

// 通用字节数组转任意维度数组方法
private static Array ConvertArrayFromBytes(byte[] buffer, Type arrayType, Array existingArray, bool isLittleEndian = false)
{
    Type elementType = arrayType.GetElementType();
    int elementSize = Marshal.SizeOf(elementType);
    int bufferOffset = 0;

    // 遍历多维数组所有索引位置赋值
    foreach (var indices in GetAllArrayIndices(existingArray))
    {
        byte[] elementBuf = new byte[elementSize];
        Buffer.BlockCopy(buffer, bufferOffset, elementBuf, 0, elementSize);
        existingArray.SetValue(ConvertFromBytes(elementBuf, elementType, isLittleEndian), indices);
        bufferOffset += elementSize;
    }
    return existingArray;
}

// 辅助方法:获取多维数组的所有索引组合
private static IEnumerable<int[]> GetAllArrayIndices(Array array)
{
    int[] indices = new int[array.Rank];
    IEnumerable<int[]> result = new[] { indices };
    for (int i = 0; i < array.Rank; i++)
    {
        int dim = i;
        result = result.SelectMany(
            prev => Enumerable.Range(0, array.GetLength(dim)), 
            (prev, idx) => prev.Take(dim).Append(idx).Concat(prev.Skip(dim + 1)).ToArray()
        );
    }
    return result;
}

3. 替换原有遍历赋值逻辑

Type type = myData.GetType();
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
FieldInfo[] fields = type.GetFields(flags);
// 非Windows设备通常为大端,此处根据实际情况调整
const bool DeviceIsLittleEndian = false;

foreach (FieldInfo field in fields)
{
    if (field.FieldType.IsArray)
    {
        Array existArray = (Array)field.GetValue(myData);
        int elementSize = Marshal.SizeOf(field.FieldType.GetElementType());
        int totalBytes = existArray.Length * elementSize;
        byte[] buffer = br.ReadBytes(totalBytes);
        field.SetValue(myData, ConvertArrayFromBytes(buffer, field.FieldType, existArray, DeviceIsLittleEndian));
    }
    else
    {
        int readSize = Marshal.SizeOf(field.FieldType);
        if (readSize > 0)
        {
            byte[] buffer = br.ReadBytes(readSize);
            field.SetValue(myData, ConvertFromBytes(buffer, field.FieldType, DeviceIsLittleEndian));
        }
    }
}

扩展优化建议

如果后续固件升级导致结构变动,只需要给不同版本的类的字段添加自定义特性,标记字段顺序、数组维度等信息,解析时通过反射读取特性即可,无需修改核心解析逻辑,可维护性极高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 19:27:04