将字节数组复制到C#中的类/结构中的各个字段

Jam*_*sPD 6 c# byte bytearray memcpy

在下面的示例C#代码中,我有一个从套接字读取的字节数组.我想将数据解析为'exampleClass'的各个字段(前8个字节到64位变量'field1',接下来4个字节到32位变量'field2'等)

using System;
namespace CsByteCopy
{
  class Program
  {
    class ExampleClass
    {
      public UInt64 field1;
      public UInt32 field2;
      public UInt16 field3;
      public byte[] field4 = new byte[18];
    }

    static void Main(string[] args)
    {
      byte[] exampleData =
      {
        // These 8 bytes should go in 'field1'
        0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
        // These 4 bytes should go in 'field2'
        0x08,0x09,0x0A,0x0B,
        // These 2 bytes should go in 'field3'
        0x0C,0x0D,
        // These 18 * 1 bytes should go in 'field4'
        0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
      };

      ExampleClass exampleClass = new ExampleClass();
      // Perform copy
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

自从我上次使用C以来已经很长时间了,但是如果我没记错的话,我可能已经能够通过单个memcpy()调用来填充类中的所有字段.在C#中填充'exampleClass'字段的最有效方法是什么?

Chr*_*ens 14

你有很多选择,最好的选择通常取决于你的程序需要/可以处理什么以及你想要多少速度.有很多文章解释了使用数据填充类或结构的不同方法.

二进制序列化是一种方法.这需要您编写自定义序列化程序,这非常简单.有关这方面的MSDN文章显示它并不太难.

您可以编写一个私有构造函数,它接受字节数组并使用BinaryReader或BitConverter类从字节数组中读取(您必须将其包装在MemoryStreamfor中BinaryReader)或简单地将字节数组的部分转换为值你需要(BitConverter).在这种情况下,BitConverter您还需要使用Buffer.BlockCopy将字节数组的剩余数据复制到类中的字节数组字段

第三种方法,通常也是最快的方法,是将您的类转换为结构并使用不安全的代码将字节数组转换为该结构.像这样的东西:

unsafe struct ExampleClass
{
   public ulong field1;
   public uint field2
   public ushort field3
   public fixed byte field4[18];

   public static ExampleClass ReadStruct(byte[] data)
   {
       fixed (byte* pb = &data[0])
       {
           return *(ExampleClass*)pb;
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

当然,上述代码仅在您使用不安全代码时才有效.此外,将类转换为结构也可能不是您正在寻找的.在大多数情况下,结构通过值传递给函数,因此调用方法复制整个结构(在本例中为32个字节)而不是传递引用(4或8个字节,具体取决于CPU体系结构),并且可能会降低效率程序.结构通过值传递有例外,您可以使用自己喜欢的搜索引擎.

如果你不能使用不安全的代码,那么Marshal.PtrToStructure也会使用与上面代码相​​同的代码,但速度要慢10倍.您还需要使用该MarshalAs属性来指定数组的大小,而不是使用fixed关键字(这是不安全的).此时,您可以使用BinaryReader/BitConverter,因为它将比编组类更快.


Hog*_*gan 3

我想你想要这个:

在这里,通过更改 field4 中的缓冲区,您还可以更改其他 3 个特定类型。

[StructLayout(LayoutKind.Explicit, Size=8)]
struct UValue
{
   [FieldOffset(0)]
   public fixed byte field4[18]; // 18 bytes long

   [FieldOffset(0)]
   public uint64 field1;

   [FieldOffset(8)]
   public Uint32 field2

   [FieldOffset(12)]
   public Uint16 field3

}
Run Code Online (Sandbox Code Playgroud)

你可能想要这个:

在这里,通过更改 fieldload 中的缓冲区,您可以像上面那样更改其他缓冲区,但最后还有另一个字节缓冲区。

[StructLayout(LayoutKind.Explicit, Size=8)]
struct UValue
{
   [FieldOffset(0)]
   public fixed byte fieldload[38]; // modify this to modify others

   [FieldOffset(0)]
   public uint64 field1;

   [FieldOffset(8)]
   public Uint32 field2

   [FieldOffset(12)]
   public Uint16 field3

   [FieldOffset(14)]
   public fixed byte field4[18]; // 18 bytes long
}
Run Code Online (Sandbox Code Playgroud)