无法访问Memory<T>,最终选择了选项(2),但不需要编组,只需强制转换:在unsafe struct 中使用fixed 字节数组,并按如下方式向/从这些字节进行转换:
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class TestStructWithFixed : MonoBehaviour
{
public const int MAX = 5;
public const int SIZEOF_ELEMENT = 8;
public struct Element
{
public uint x;
public uint y;
//8 bytes
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct Container
{
public int id; //4 bytes
public unsafe fixed byte bytes[MAX * SIZEOF_ELEMENT];
}
public Container container;
void Start ()
{
Debug.Log("SizeOf container="+Marshal.SizeOf(container));
Debug.Log("SizeOf element ="+Marshal.SizeOf(new Element()));
unsafe
{
Element* elements;
fixed (byte* bytes = container.bytes)
{
elements = (Element*) bytes;
//show zeroed bytes first...
for (int i = 0; i < MAX; i++)
Debug.Log("i="+i+":"+elements[i].x);
//low order bytes of Element.x are at 0, 8, 16, 24, 32 respectively for the 5 Elements
bytes[0 * SIZEOF_ELEMENT] = 4;
bytes[4 * SIZEOF_ELEMENT] = 7;
}
elements[2].x = 99;
//show modified bytes as part of Element...
for (int i = 0; i < MAX; i++)
Debug.Log("i="+i+":"+elements[i].x); //shows 4, 99, 7 at [0], [2], [4] respectively
}
}
}
unsafe 访问速度非常快,而且没有编组或复制 - 这正是我想要的。
如果可能对所有struct 成员使用4 字节ints 或floats,您甚至可以更好地将fixed 缓冲区基于这种类型(uint 始终一个干净的选择) - 易于调试。
2021 年更新
今年我重新讨论了这个主题,在 Unity 5 中进行原型设计(由于编译/迭代时间快)。
坚持使用一个非常大的字节数组并在托管代码中使用它会更容易,而不是使用fixed + unsafe(顺便说一下,从 C# 7.3 开始,it is no longer necessary to use the fixed keyword every time to pin a fixed-size buffer 才能访问它) .
fixed 我们失去了类型安全性;这是互操作数据的一个自然缺点——无论是原生数据还是托管数据的互操作; CPU和GPU;或 Unity 主线程代码和用于新 Burst / Jobs 系统的代码之间。这同样适用于托管字节缓冲区。
因此,可以更轻松地接受使用无类型托管缓冲区并自己编写偏移量 + 大小。 fixed / unsafe 提供(一点)更多便利,但不是很多,因为您同样必须指定编译时结构字段偏移量,并在每次数据设计更改时更改这些偏移量。至少对于托管 VLA,我可以对代码中的偏移量求和,但这确实意味着这些不是编译时常量,因此会失去一些优化。
与托管 VLA(在 Unity 中)相比,以这种方式分配 fixed 缓冲区的唯一真正好处是,对于后者,GC 有可能在播放过程中将您的整个数据模型移动到其他地方,这可能会导致打嗝,尽管我还没有看到这在生产中有多严重。
托管数组are not, however, directly supported by Burst。