2012-10-21 47 views
3

我有關於串行通信中的消息解析的想法,有許多種不同形式的數據包。但它們都是通過字節數組發送的。我想使用聯合作爲C#與字節數組

所以我想用union來解析每條消息。 但它運行不正常。 下面的代碼是示例代碼,我在錯誤

[StructLayout(LayoutKind.Explicit, Size=12)] 
public struct UnionPacket 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] 
    public byte[] data; 

    [FieldOffset(0)] 
    public float Time; 
    [FieldOffset(4)] 
    public Int16 CoordX; 
    [FieldOffset(6)] 
    public Int16 CoordY; 
    [FieldOffset(8)] 
    public byte Red; 
    [FieldOffset(9)] 
    public byte Green; 
    [FieldOffset(10)] 
    public byte Blue; 
    [FieldOffset(11)] 
    public byte Alpha; 
} 

,如果這是可能的,這將是非常高興的,但事實並非如此。此代碼發生TypeLoadException「...因爲它包含偏移量爲0的對象字段,該對象字段被非對象字段錯誤地對齊或重疊。」

所以我改變了一些這樣的代碼

[StructLayout(LayoutKind.Explicit, Size= 12)] 
public struct UnionPacket 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] 
    [FieldOffset(0)] 
    public byte[] data; 

    //[FieldOffset(0)] 
    //public float Time; 
    [FieldOffset(4)] 
    public Int16 CoordX; 
    [FieldOffset(6)] 
    public Int16 CoordY; 
    [FieldOffset(8)] 
    public byte Red; 
    [FieldOffset(9)] 
    public byte Green; 
    [FieldOffset(10)] 
    public byte Blue; 
    [FieldOffset(11)] 
    public byte Alpha; 
} 

測試,我只是禁止時間字段,偏移量爲0,而這並沒有出現異常。但是,如果我更改其他字段,它不會更改字節數組。我認爲字節數組的實際內存位置被分配在其他堆中,所以無法完成。

有什麼方法可以解決C#中的這個問題嗎?只有C++或C可以解決這個問題? 如果我用繼承,這是可能的嗎?

P.S.對不起我的英語不好

回答

2

我不是100%肯定你正在嘗試做的,但:

第一種方法,與存儲結構的內部陣列是可能的,如果你有固定/不安全使用關鍵字。我不知道這對你是否可行。所以像這種有代碼應工作:

[StructLayout(LayoutKind.Explicit, Size = 12)] 
public unsafe struct UnionPacket 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] 
    [FieldOffset(0)] 
    public fixed byte data[12]; 

    [FieldOffset(0)] 
    public float Time; 
    [FieldOffset(4)] 
    public Int16 CoordX; 
    [FieldOffset(6)] 
    public Int16 CoordY; 
    [FieldOffset(8)] 
    public byte Red; 
    [FieldOffset(9)] 
    public byte Green; 
    [FieldOffset(10)] 
    public byte Blue; 
    [FieldOffset(11)] 
    public byte Alpha; 
} 

當然,你必須啓用VS不安全的代碼塊,並使用它繞到你的結構:

unsafe 
{ 
    var u = new UnionPacket(); 
    for (byte i = 0; i < 12; i++) 
    { 
     u.data[i] = i; 
    } 
    Console.WriteLine(u.Time); 
    Console.WriteLine(u.CoordX); 
    Console.WriteLine(u.CoordY);   
    Console.WriteLine(u.Red); 
    Console.WriteLine(u.Green); 
    Console.WriteLine(u.Blue); 
    Console.WriteLine(u.Alpha); 
} 

其他的辦法是 - 只忘記了這個陣列內部結構,以及使用Marshal.Copy處理解析:

[StructLayout(LayoutKind.Explicit, Size = 12)] 
public struct UnionPacket2 
{ 
    [FieldOffset(0)] 
    public float Time; 
    [FieldOffset(4)] 
    public Int16 CoordX; 
    [FieldOffset(6)] 
    public Int16 CoordY; 
    [FieldOffset(8)] 
    public byte Red; 
    [FieldOffset(9)] 
    public byte Green; 
    [FieldOffset(10)] 
    public byte Blue; 
    [FieldOffset(11)] 
    public byte Alpha; 
} 

static void Main(string[] args) 
{ 
    var len = Marshal.SizeOf(typeof(UnionPacket2)); 
    var buffer = new byte[len]; 
    for (byte i = 0; i < len; i++) 
    { 
     buffer[i] = i; 
    } 

    var ptr = Marshal.AllocHGlobal(len); 
    Marshal.Copy(buffer, 0, ptr, len); 
    var u = (UnionPacket2)Marshal.PtrToStructure(ptr, typeof(UnionPacket2)); 
    Marshal.FreeHGlobal(ptr); 
    Console.WriteLine(u.Time); 
    Console.WriteLine(u.CoordX); 
    Console.WriteLine(u.CoordY); 
    Console.WriteLine(u.Red); 
    Console.WriteLine(u.Green); 
    Console.WriteLine(u.Blue); 
    Console.WriteLine(u.Alpha); 
} 
+0

三江源,我使用的第二方法,因爲使用固定陣列是難以替代DATAS,三江源。 –

相關問題