代码改变世界

[海康开发笔记]将内存片段格式化为C#类对象时需要注意对象的字段顺序

2010-03-28 18:28  uonun  阅读(381)  评论(0编辑  收藏  举报

将内存片段byte[] data 格式化为结构或类实例时,结构/类的属性或字段定义顺序将影响格式化结果。

如海康设备向注册中心发送的数据表中,包头信息类的定义:

/// <summary>
/// 设备向服务器:MsgRetHeader 
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class MsgRetHeader : CmdHeader
{
    /// <summary>
    /// 海康与平台厂家协商定义的标记,此标记在前端PU与平台对接中保持一致,不能单方面修改,现阶段信令部分为0x53584C54,码流部分为0x53585354
    /// </summary>
    public uint tag;

    /// <summary>
    /// 前端PU接入CMS的设备标识(简称PUID),由平台分配,并确保前端PU唯一
    /// </summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
    public string deviceId;

    /// <summary>
    /// 根据不同的功能定义使用,不使用时默认为0,与通道相关的码流和参数配置时候需填写chan字段
    /// </summary>
    public uint chan;

    /// <summary>
    /// 根据不同的功能定义使用,不使用时默认为0
    /// </summary>
    public uint devideType;

    /// <summary>
    /// XML封装的消息体内容长度,用于传输中消息数据的接收,以字节计算,若此值为0,表示XML内容不存在
    /// </summary>
    public uint streamLength;

    /// <summary>
    /// 保留字段
    /// </summary>
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string res;
}

MsgRetHeader 类的各个字段的定义顺序必须和设备发送数据包时所用的结构体中各字段的定义顺序一致(数据包结构体是C++程序,由TCP发送),满足该条件后即可使用如下方法将byte[]转化为C#中的类实例:

/// <summary>
/// 将byte[]转换为结构体
/// </summary>
/// <param name="bytes"></param>
/// <param name="strcutType"></param>
/// <returns></returns>
public static object BytesToStruct(byte[] bytes, Type strcutType)
{
    int size = Marshal.SizeOf(strcutType);
    IntPtr buffer = Marshal.AllocHGlobal(size);
    try
    {
        Marshal.Copy(bytes, 0, buffer, size);
        return Marshal.PtrToStructure(buffer, strcutType);
    }
    finally
    {
        Marshal.FreeHGlobal(buffer);
    }
}

如果交换了字段定义顺序,则转化出来的类实例字段值将产生逻辑错误。