带有数组的结构的 C# 编组

Pau*_*erg 2 c# arrays struct runtime marshalling

假设我有一个类似于

public struct MyStruct
{
    public float[] a;
}
Run Code Online (Sandbox Code Playgroud)

并且我想用一些自定义数组大小实例化一个这样的结构(在这个例子中假设为 2)。然后我将它编组到一个字节数组中。

MyStruct s = new MyStruct();
s.a = new float[2];
s.a[0] = 1.0f;
s.a[1] = 2.0f;

byte[] buffer = new byte[Marshal.SizeOf(typeof(MyStruct))];
GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);

try
{
    Marshal.StructureToPtr(s, gcHandle.AddrOfPinnedObject(), false);

    for (int i = 0; i < buffer.Length; i++)
    {
        System.Console.WriteLine(buffer[i].ToString("x2"));
    }
}
finally
{
    gcHandle.Free();
}
Run Code Online (Sandbox Code Playgroud)

这在我的 byte[] 中只给了我 4 个字节,它们看起来像一个指针值,而不是 1.0f 或 2.0f 的值。我已经四处寻找使这项工作起作用的方法,但到目前为止我能找到的都是类似的例子,其中结构数组的大小是提前知道的。没有办法做到这一点吗?

Fra*_*tyx 5

StructureToPtr与包含值类型只(INT,炭,浮点型,其他结构)的结构确实仅工作。float[]是一个引用类型,所以你真的得到了一种指针(你不能真正使用它,因为它是一个托管指针)。如果要将数组复制到固定内存,则必须Marshal.Copy直接在s.a浮点数组上使用其中一个函数。

类似的东西。(我没有真正测试过)

byte[] buffer = new byte[sizeof(float) * s.a.Length];
GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Run Code Online (Sandbox Code Playgroud)

进而

Marshal.Copy(s.a, 0, gcHandle.AddrOfPinnedObject(), s.a.Length);
Run Code Online (Sandbox Code Playgroud)

更新

我必须纠正自己。您还可以通过以这种方式声明您的结构来获得您想要的:

 [StructLayout(LayoutKind.Sequential)]
 public struct MyStruct
 {
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
     public float[] a;
 }
Run Code Online (Sandbox Code Playgroud)

如您所见,您必须在设计时固定浮点数组的大小。