c#Marshal将字节数组转为结构封装协议
解析⽹络协议如果使⽤依次读取字节的⽅式效率太低,可以直接通过结构体映射的⽅式来转换数据,如下1. 定义需要转换的结构体
需要让结构体数据顺序排列并对齐
依次定义每⼀个属性的长度即可,需要注意定义的数据类型的⼤⼩要与UnmanagedType类型定义的⼤⼩⼀直
否则会报 “不能作为⾮托管结构进⾏封送处理;⽆法计算有意义的⼤⼩或偏移量”
// [StructLayout(LayoutKind.Sequential, Pack = 1)] //顺序排列,并按1字节对齐
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
sizeof结构体大小public struct SEG2
{
/// <summary>
/// ⽂件描述符  0-1
/// 若不是3A55H/553AH则不是SEG2⽂件
/// </summary>
[MarshalAs(UnmanagedType.U1)]
public byte Descriptor0;
[MarshalAs(UnmanagedType.U1)]
public byte Descriptor1;
}
2. 将字节数组转为对象
var fileByte = File.ReadAllBytes(testFile);
//创建指定类型的指针(从进程的⾮托管内存中分配内存)
IntPtr paramPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SEG2)));
//将字节数组复制到指针
Marshal.Copy(fileByte, 0, paramPtr, Marshal.SizeOf(typeof(SEG2)));
////将指定的指针转为特定类型的对象(将数据从⾮托管内存块封送到新分配的指定类型的托管对象)
SEG2 obj = (SEG2)Marshal.PtrToStructure(paramPtr, typeof(SEG2));
3. 将对象从托管对象复制到内存块
//将对象复制给指针所指内存
var obj=new object();
Marshal.StructureToPtr(obj, paramPtr, true);
4. 释放内存,内存在⾮托管块需要⼿动释放
Marshal.FreeHGlobal(paramPtr);
5. 复杂对象
如果为数组这类⾮固定位数的对象,可以通过多次调⽤的⽅式依次将托管对象与⾮托管对象互相转换
形式上更像c/c++利⽤指针对内存进⾏操作