我正在用C#实现一个非托管数组类,我需要一些OpenGL调用。
这很好,但我遇到了障碍。以下代码无法编译,我理解为什么,但我怎样才能使它工作?
public T this[int i]
{
get { return *((T*)arrayPtr + i); }
set { *((T*)arrayPtr + i) = value; }
}
我认为如果我确保T是结构
,它可能会有用unsafe class FixedArray<T> where T : struct
也不起作用......
我怎样才能在功能上与我上面尝试的内容相提并论?
编辑:我正在使用Marshal.AllocHGlobal()的非托管数组,以便我的数组被修复,GC不会移动它。当你调用它时,OpenGL实际上并不处理指令,OpenGL会在函数返回后很长时间内尝试访问数组。如果这有帮助,这就是全班:
unsafe class FixedArray<T> where T : struct
{
IntPtr arrayPtr;
public T this[int i]
{
get { return *((T*)arrayPtr + i); }
set { *((T*)arrayPtr + i) = value; }
}
public FixedArray(int length)
{
arrayPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)) * length);
}
~FixedArray()
{
Marshal.FreeHGlobal(arrayPtr);
}
}
错误消息是无法获取地址,获取大小,或声明指向托管类型的指针('T')
答案 0 :(得分:5)
我很确定无法编译代码。对于您的代码(T*)arrayPtr + i
,当arrayPtr + i * 4
为T
时会计算int
,arrayPtr + i * 8
为T
时会计算long
。由于CLR无法替换4,8或其他任何sizeof(T)
,因此该代码无效。
您需要做的是使用Marshal
为您完成所有工作。编译,但我没有测试过:
unsafe class FixedArray<T> where T : struct
{
IntPtr arrayPtr;
int sizeofT { get { return Marshal.SizeOf(typeof(T)); } }
public T this[int i]
{
get
{
return (T)Marshal.PtrToStructure(arrayPtr + i * sizeofT, typeof(T));
}
set
{
Marshal.StructureToPtr(value, arrayPtr + i * sizeofT, false);
}
}
public FixedArray(int length)
{
arrayPtr = Marshal.AllocHGlobal(sizeofT * length);
}
~FixedArray()
{
Marshal.FreeHGlobal(arrayPtr);
}
}
答案 1 :(得分:4)
您不需要非托管数组。
您可以正常声明托管数组:
var myArray = new MyStruct[13];
然后使用GCHandle
类将其固定在内存中并获取其地址:
var handle = GCHandle.Alloc(myArray, GCHandleType.Pinned);
IntPtr address = handle.AddrOfPinnedObject();
在您调用handle.Free
之前,该数组将存在于该内存地址中。如果您从未致电Free
,那么它将一直待在您的程序退出之前。
答案 2 :(得分:0)
现在在c#7.3中是可能的。您需要指定unmanaged
通用约束:
unsafe class FixedArray<T> where T : unmanaged
{
T* arrayPtr;
public T this[int i]
{
get { return *(arrayPtr + i); }
set { *(arrayPtr + i) = value; }
}
public FixedArray(int length)
{
arrayPtr = (T*)Marshal.AllocHGlobal(sizeof(T) * length);
}
~FixedArray()
{
Marshal.FreeHGlobal((IntPtr)arrayPtr);
}
}
不幸的是仍然存在局限性。例如,类型T
不能包含通用类型,因此FixedArray
暂时不能包含其他FixedArray
。