2014-10-10 22 views
0

代碼爲NET 2.0。C#。如何快速將字節插入結構?

我寫函數ByteArrayToObject在結構中插入偏移量字節,但它可以快速嗎? 計劃中會有很多結構需要添加更改後的網絡信息。如果我可以將這些字節快速插入到正確的位置,它將作爲一個大的結構組織在協議中。 謝謝你的幫助。

在我的情況下,我不喜歡每次都替換必須執行對象func ObjectToByteArray的所有副本的字節。

/// <summary> Convert an object struct to a byte array </summary> 
     private static byte[] ObjectToByteArray(Object obj) 
     { 

      var size = Marshal.SizeOf(obj); 
      // Both managed and unmanaged buffers required. 
      var bytes = new byte[size]; 
      var ptr = Marshal.AllocHGlobal(size); 
      // Copy object byte-to-byte to unmanaged memory. 
      Marshal.StructureToPtr(obj, ptr, false); 
      // Copy data from unmanaged memory to managed buffer. 
      Marshal.Copy(ptr, bytes, 0, size); 
      // Release unmanaged memory. 
      Marshal.FreeHGlobal(ptr); 
      return bytes; 
     } 

     /// <summary> Need Faster ? </summary> 
     public static T ByteArrayToObject<T>(ref T obj, int StartOffset, params byte[] bytes) 
     { 
      int size = Marshal.SizeOf(obj); 
      int Length = (bytes.Length > size) ? size : bytes.Length; 
      byte[] Allbytes = ObjectToByteArray(obj); 
      Array.Copy(bytes, 0, Allbytes, StartOffset, Length - StartOffset); 
      var ptr = Marshal.AllocHGlobal(size); 
      Marshal.Copy(Allbytes, 0, ptr, Length); 
      obj = (T)Marshal.PtrToStructure(ptr, typeof(T)); 
      Marshal.FreeHGlobal(ptr); 
      return obj; 
     } 

示例使用

[Serializable] 
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1, CharSet = System.Runtime.InteropServices.CharSet.Ansi)] 
    struct Protocol 
    { 
     public byte f0; 
     public byte f1; 
     public short f2; 
     public byte f3; 
     public long f4;    
     [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 20000)] 
     public int[] Array; // 20000 

     } 

     System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); 
     for (byte i = 1; i < 10; i++) 
     { 
      sw.Reset(); 
      sw.Start(); 
      ob = ByteArrayToObject<Protocol>(ref ob,1, i, 0x11, i, 0x22, i); 
      sw.Stop(); 
      Console.WriteLine("Tick =" + sw.ElapsedTicks); 
     } 

輸出

Tick =9940 
Tick =686 
Tick =593 
Tick =474 
Tick =562 
Tick =5283 
Tick =193 
Tick =173 
Tick =164 
+1

好傢伙!你究竟想要做什麼?編輯:如果它只是一個結構類型,不安全會更快,但是你將不得不爲每個類型實現相同的代碼。 – leppie 2014-10-10 07:40:08

+0

只是尋找協議工作的最佳方式。 – askeet 2014-10-10 07:57:41

+0

看看我的答案。如果你真的想要速度,可以爲你工作。將會有更多的工作,但每種結構類型都可以使用相同的方法。 – leppie 2014-10-10 07:59:09

回答

0

重寫了一個小

public static unsafe void ByteArrayToEx(ref Ex value, int offset, params byte[] bytes) 
    { 
     // you should add some safely nets here sizeof(Ex) should used for size of struct 

     fixed (Ex* obj = &value) 
     { 
      byte* p = (byte*)obj; 
      foreach (var b in bytes) 
      { 
       p[offset++] = b; 
      } 
     } 
     // dont return value, it is expensive! 
    } 
1

這是太長了評論,但對不安全的做法擴大:

unsafe struct Ex 
{ 
    public byte f0,f1,f2,f3,f4; 
    public fixed int buffer[20000]; 
} 

class Program 
{ 
    public static unsafe void ByteArrayToEx(Ex* obj, int offset, params byte[] bytes) 
    { 
    // you should add some safely nets here sizeof(Ex) should used for size of struct 
    byte* p = (byte*)obj; 
    foreach (var b in bytes) 
    { 
     p[offset++] = b; 
    } 
    // dont return value, it is expensive! 
    } 

    unsafe static void Main(string[] args) 
    { 
    Stopwatch sw = new Stopwatch(); 
    Console.WriteLine(Stopwatch.Frequency); 
    Ex e = new Ex { f0 = 0, f1 = 1, f2 = 2, f3 = 3, f4 = 4 }; 
    ByteArrayToEx(&e, 2, 5, 6, 7); 
    for (int i = 0; i < 10; i++) { 
     sw.Restart(); 
     ByteArrayToEx(&e, 2, (byte) i, 6, 7); 
     sw.Stop(); 
     Console.WriteLine(sw.ElapsedTicks); 
    } 
    } 
} 

這可能是也可能不適合你。也不要返回值。你已經在改變它的指針了。返回這樣一個大結構的副本會在每次調用時添加10個記號。

此外,在進行臺階打標時,您至少需要進行1次熱身。這就是爲什麼第一個數字很差。

結果在我的電腦:

3312929 
4 
2 
0 
0 
0 
0 
0 
0 
0 
0 
+1

有人將不得不開始記錄他們的Stopwatch.Frequency或使用Elapsed。這些數字完全沒有意義進行任何形式的比較。 80納秒*不是很多時間。 – 2014-10-10 08:12:18

+0

@HansPassant:是的...我會補充說:)編輯:使用'Elapsed'由於小測試是毫無意義的。 – leppie 2014-10-10 08:12:59

+0

謝謝。但是,如何使用模板? – askeet 2014-10-10 09:34:47