2015-10-17 47 views
0

我有一个数组全该类BlockCopy一个类?获得“对象必须是原语的数组”

public class TransformData { 
    public float pos_x, pos_y, pos_z; 
    public float rot_x, rot_y, rot_z; 
    public float scale_x, scale_y, scale_z; 
} 

我想这个数组的字节转换使用的实例:所以

byte[] byteArray = new byte[transformArrayByteSizeHere]; 
uffer.BlockCopy(transformArrayHere, 0, byteArray, 0, transformArrayByteSizeHere); 

我可以写一个二进制文件。但是我得到:“对象必须是一个基元数组。”我收集这意味着我只能转换为C#已知类型的字节,这样的浮点数?但为什么?我的课充满了原始类型...我觉得它应该知道如何做到这一点。我错过了什么?

+0

TransformData不是原始的。如果你试图写出一个TransformData数组,那不是一个原始数组 – Joe

回答

4

你应该知道的一件事是引用类型的数组(在C#中class关键字表示引用类型)甚至不是连续的。有一个缓冲区连续存放所有指针,但内容本身分散在GC堆中的每个地方。

更改为一个结构(值类型)可以解决这个问题,事实上,您可以使用p/invoke或C#原始指针进行blit处理。但是Buffer.BlockCopy不够聪明,看不到用户定义的结构是由原语组成的,因此可以复制,它只是拒绝所有化合物类型。因此,您必须在使用不安全代码的批量复制之间下决心,或者手动逐个元素逐个元素地执行此操作。

快速的方法,要求unsafe关键词,大致是:

// assumes TransformData is struct, not class 
fixed(TransformData* p = &transformArray[0]) 
    Marshal.Copy(new IntPtr(p), byteArray, 0, byteArray.Length); 
+0

我发现了不安全的方法,并使用非托管代码(我相信C#原始指针属于此类别?)来执行此操作。谢谢,我会考虑的。 – Stradigos

+0

C#原始指针*不是非托管代码,但需要大部分相同的代码信任。 –

+0

很好的回答。谢谢。 –

1

与int/byte/float的基本数组不同,关于其他类型在内存中的存在方式没有二进制标准。因此,低级操作对于一般类型是不实际的(除了在某些情况下逐位复制可能导致一致性问题 - 即克隆FileStreamDrawing.Pen对象没有更新内部计数器将导致非常不好的问题)。

通常使用良好定义的序列化格式(XML/JSON,如果文本很好)来存储数据会更好。如果你需要更多的紧凑的二进制格式的许多对象Binary Serialization会工作。如果你需要与非.Net系统的兼容性,像原始buff可能是更好的选择(请参阅When should I use XML Serialization vs. Binary Serialization in the .NET framework?讨论)。

在所有序列化的情况下,您需要知道有大量类型由于运行时数据的存在而无法序列化/反序列化(即连接/服务类型如SqlConnection或OS级别类型 - 文件,绘图对象)。

如果您确实想复制字节 - 将您的类型限制为某些struct可能与Marshl.Copy一起使用 - 请参阅How to convert a structure to a byte array in C#?

+0

那真令人失望。我的意思是,它已经知道我的TransformData类的大小,因为它可以用“new”来实例化它,并且知道它的大小你必须知道其中的数据类型......我只是不明白为什么它在意什么类型因为它们仍然只是二进制数据。我想我在C++上花了太多时间?我很确定这是我以前使用像myFunc(&myArray [0],size)这样的引用完成的。 – Stradigos

+0

@Stradigos C++? 'class MyString {public char * text;}'几乎没有意义复制为字节......或者将VMT指针保存到文件中 - 稍后您将如何处理? –

+0

@AlexeiLevenkov:他的UDT中没有任何指针......并且可能没有意识到他在阵列中有他们。 –

0

我认为最好的办法将是你的类更改为一个结构和使用Array.Copy,如果可能的话。

但是请注意,用于拷贝到同一个数组中的“Array.Copy”执行速度很慢,速度很慢(比C++慢两倍)。 (如2017年6月1日的)

这是代码,我做调用外部C代码部分:

[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false), SuppressUnmanagedCodeSecurity] 
     public static unsafe extern void* CopyMemory(void* dest, void* src, ulong count); 


     // ************************************************************************ 
     /// <summary> 
     /// Insert an "item" at "index" position into an "array" which could be bigger 
     /// than the real count of items ("countOfValidItems") in it. 
     /// </summary> 
     /// <param name="array"></param> 
     /// <param name="item"></param> 
     /// <param name="index"></param> 
     /// <param name="countOfValidItems"></param> 
     [MethodImpl(MethodImplOptions.AggressiveInlining)] 
     unsafe public static void InsertItemPinvokeC(Point[] array, Point item, int index, ref int countOfValidItems) 
     { 
      if (countOfValidItems >= array.Length) 
      { 
       Point[] dest = new Point[array.Length * 2]; 

       // The next 2 calls are replaced by a call to CopyMemory (memcopy from defined in C library "msvcrt.dll"). 
       // Array.Copy(array, 0, dest, 0, index); 
       // Array.Copy(array, index, dest, index + 1, countOfValidItems - index); 

       //Buffer.BlockCopy(array, 0, dest, 0, (countOfValidItems - index) * sizeof(Point)); 
       //Buffer.BlockCopy(array, index * sizeof(Point), dest, (index + 1) * sizeof(Point), (countOfValidItems - index) * sizeof(Point)); 

       fixed (Point* s = array) 
       { 
        fixed (Point* d = dest) 
        { 
         CopyMemory(d, s, (ulong)(index * sizeof(Point))); 
         CopyMemory(d + ((index + 1) * sizeof(Point)), s + (index * sizeof(Point)), (ulong)((countOfValidItems - index) * sizeof(Point))); 
        } 
       } 

       array = dest; 
      } 
      else 
      { 
       // Array.Copy(array, index, array, index + 1, countOfValidItems - index); 

       // Buffer.BlockCopy(array, index * sizeof(Point), array, (index + 1) * sizeof(Point), (countOfValidItems - index) * sizeof(Point)); 

       fixed (Point* p = array) 
       { 
        CopyMemory(p + ((index + 1) * sizeof(Point)), p + (index * sizeof(Point)), (ulong)((countOfValidItems - index) * sizeof(Point))); 
       } 
      } 

      array[index] = item; 
      countOfValidItems++; 
     } 
相关问题