我创建了这个非托管包数据持有者,它允许我在严格的非托管上下文中使用它。但是,我认为对齐似乎存在一些问题。我就是不明白那是什么...
这是整个结构代码:
using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace Game.Runtime.Utility
{
public struct BagUnmanaged : IDisposable
{
private NativeList<byte> data;
private NativeList<int> offsets;
private int currentOffset;
public BagUnmanaged(Allocator allocator)
{
data = new NativeList<byte>(allocator);
offsets = new NativeList<int>(allocator);
currentOffset = 0;
}
private int AlignOffset(int offset, int alignment)
{
return (offset + (alignment - 1)) & ~(alignment - 1);
}
public unsafe void Add<T>(T value) where T : unmanaged
{
int size = UnsafeUtility.SizeOf<T>();
int alignment = UnsafeUtility.AlignOf<T>();
currentOffset = AlignOffset(currentOffset, alignment);
offsets.Add(currentOffset);
data.ResizeUninitialized(currentOffset + size);
byte* ptr = data.GetUnsafePtr();
UnsafeUtility.CopyStructureToPtr(ref value, ptr + currentOffset);
currentOffset += size;
}
public unsafe T Get<T>(int index) where T : unmanaged
{
int elementOffset = offsets[index];
byte* ptr = data.GetUnsafeReadOnlyPtr();
return UnsafeUtility.ReadArrayElementWithStride<T>(ptr, elementOffset, UnsafeUtility.SizeOf<T>());
}
public unsafe void Set<T>(int index, T value) where T : unmanaged
{
int elementOffset = offsets[index];
byte* ptr = data.GetUnsafePtr();
UnsafeUtility.CopyStructureToPtr(ref value, ptr + elementOffset);
}
public void Dispose()
{
if (data.IsCreated)
{ data.Dispose(); }
if (offsets.IsCreated)
{ offsets.Dispose(); }
}
}
}
我已经测试过它,当我从包里取出它们时,float 和 bool 值似乎都是正确的,但是,添加它和更新后的 int 值完全错误。
private void Start()
{
using BagUnmanaged bag = new(Allocator.Persistent);
bag.Add(5.0F);
bag.Add(1);
bag.Add(true);
var f = bag.Get<float>(0);
var i = bag.Get<int>(1);
var b = bag.Get<bool>(2);
Console.WriteLine("Float {0}", f);
Console.WriteLine("Int {0}", i); // Returns sometimes 0 sometimes -1 or 80
Console.WriteLine("Boolean {0}", b);
bag.Set(1, 90);
i = bag.Get<int>(1);
Console.WriteLine("Updated Int {0}", i); // Same incorrect value as above
}
您的问题在于使用
UnsafeUtility.ReadArrayElementWithStride
进行阅读:
ReadArrayElementWithStride(destination, index, stride, value)
是一个只执行 Write(destination + index * stride, value)
功能的函数。 “stride”参数是数组中包含的元素的宽度(假设所有元素的大小相同!),它将与索引相乘。第二个参数不是 offset,而是 index。所以你的阅读越界了。
解决此问题只需将您的阅读逻辑更改为使用
UnsafeUtility.CopyPtrToStructure
,即UnsafeUtility.CopyStructureToPtr
的对应部分:
public unsafe T Get<T>(int index) where T : unmanaged {
...
UnsafeUtility.CopyPtrToStructure(ptr + elementOffset, out T result);
return result;
}