2014-10-10 48 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