解析網絡協議如果使用依次讀取字節的方式效率太低,可以直接通過結構體映射的方式來轉換數據,如下
- 定義需要轉換的結構體
需要讓結構體數據順序排列並對齊
依次定義每一個屬性的長度即可,需要注意定義的數據類型的大小要與UnmanagedType類型定義的大小一直
否則會報 “不能作為非托管結構進行封送處理;無法計算有意義的大小或偏移量”
// [StructLayout(LayoutKind.Sequential, Pack = 1)] //順序排列,並按1字節對齊
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SEG2
{
/// <summary>
/// 文件描述符 0-1
/// 若不是3A55H/553AH則 不是SEG2文件
/// </summary>
[MarshalAs(UnmanagedType.U1)]
public byte Descriptor0;
[MarshalAs(UnmanagedType.U1)]
public byte Descriptor1;
}
- 將字節數組轉為對象
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));
- 將對象從托管對象復制到內存塊
//將對象復制給指針所指內存
var obj=new object();
Marshal.StructureToPtr(obj, paramPtr, true);
-
釋放內存,內存在非托管塊需要手動釋放
Marshal.FreeHGlobal(paramPtr);
- 復雜對象
如果為數組這類非固定位數的對象,可以通過多次調用的方式依次將托管對象與非托管對象互相轉換
形式上更像c/c++利用指針對內存進行操作