不能获取地址,获取大小,或声明指向托管类型('T')的指针

Wou*_*hut 6 .net c#

为什么哦为什么不允许这样做:

    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应该不是一个有效的约束?

Abi*_*n47 7

就像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上下文工作.(如果你关心那种事情.)

  • 另外,OP的签名会导致该结构的副本。如果通过引用传递了该副本,则也可以避免。静态不安全字节[] ConvertStruct &lt;T&gt;(ref T str)其中T:struct (2认同)

Dam*_*ver 5

来自 C# 规范的第 18.2 节:

不允许指针指向引用或包含引用的结构,并且指针的所指类型必须是非托管类型。

...

非托管型是下列之一:

sbytebyteshortushortintuintlongulongcharfloatdoubledecimal、 或bool

• 任何枚举类型

• 任何指针类型

• 任何用户定义的结构类型,它不是构造类型并且仅包含非托管类型的字段。

并且没有真正的方法可以通过通用约束来表达这一点。即使这个定义看起来与"blittable" 的任何定义基本相似,值得注意的是,该特定概念并未在 C# 规范中定义(甚至引用)。例如,从 MSDN 页面我们可以看到“blittable 类型的一维数组”是 blittable 但上面的规范定义似乎排除了数组。