为什么哦为什么不允许这样做:
private static unsafe byte[] ConvertStruct<T>(T str) where T: struct
{
T* ptr = &str;
int size = Marshal.SizeOf(str);
var arr = new byte[size];
Marshal.Copy((IntPtr) ptr, arr, 0, size);
return arr;
}
Run Code Online (Sandbox Code Playgroud)
我得到编译错误"不能获取地址,获取大小,或声明指向托管类型('T')的指针"
或者"结构"约束还不够?从某种意义上说,它仍然可以是一个托管结构?
我是否正确理解我的结构可能不明显?如果是这样,blittable应该不是一个有效的约束?
就像Damian_The_Unbeliever所说,你不能创建托管对象或包含托管字段的结构的非托管指针.就像我在评论中所说的那样,没有可以实现的通用约束,这将确保编译时安全性,以确保结构满足这些要求.因此,您不能指向泛型类型.
但是,可能有一种解决方法.该Marshal.StructureToPtr方法将采用结构对象并将其数据复制到IntPtr地址中.您可以结合使用它Marshall.AllocHGlobal来实现所需的功能:
private static byte[] ConvertStruct<T>(ref T str) where T : struct
{
int size = Marshal.SizeOf(str);
IntPtr arrPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, arrPtr, true);
var arr = new byte[size];
Marshal.Copy(arrPtr, arr, 0, size);
Marshal.FreeHGlobal(arrPtr);
return arr;
}
Run Code Online (Sandbox Code Playgroud)
正如Kris Vandermotten指出的那样,Marshal.AllocHGlobal实际上并不是必需的.您可以固定阵列,获取IntPtr它,然后IntPtr直接复制到:
private static unsafe byte[] ConvertStruct<T>(ref T str) where T : struct
{
int size = Marshal.SizeOf(str);
var arr = new byte[size];
fixed (byte* arrPtr = arr)
{
Marshal.StructureToPtr(str, (IntPtr)arrPtr, true);
}
return arr;
}
Run Code Online (Sandbox Code Playgroud)
但是,第一种方法的好处是它不需要unsafe上下文工作.(如果你关心那种事情.)
来自 C# 规范的第 18.2 节:
不允许指针指向引用或包含引用的结构,并且指针的所指类型必须是非托管类型。
...
的非托管型是下列之一:
•
sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、 或bool。• 任何枚举类型。
• 任何指针类型。
• 任何用户定义的结构类型,它不是构造类型并且仅包含非托管类型的字段。
并且没有真正的方法可以通过通用约束来表达这一点。即使这个定义看起来与"blittable" 的任何定义基本相似,值得注意的是,该特定概念并未在 C# 规范中定义(甚至引用)。例如,从 MSDN 页面我们可以看到“blittable 类型的一维数组”是 blittable 但上面的规范定义似乎排除了数组。
| 归档时间: |
|
| 查看次数: |
4388 次 |
| 最近记录: |