繁体   English   中英

为什么我不能使用Marshal.Copy()来更新结构?

[英]Why can I not use Marshal.Copy() to update a struct?

我有一些代码用于从字节数组中获取结构:

    public static T GetValue<T>(byte[] data, int start) where T : struct
    {
        T d = default(T);
        int elementsize = Marshal.SizeOf(typeof(T));

        GCHandle sh = GCHandle.Alloc(d, GCHandleType.Pinned);
        Marshal.Copy(data, start, sh.AddrOfPinnedObject(), elementsize);
        sh.Free();

        return d;
    }

但是,结构d永远不会被修改,并始终返回其默认值。

我已经查找了“正确”的方法,并且正在使用它,但仍然很好奇,因为我不明白为什么上面的内容不起作用。

它可以很简单:分配一些内存,d,获取指向它的指针,将一些字节复制到由此指向的内存中,返回。 不仅如此, 但是当我使用类似的代码但是d是T的数组时,它工作正常。 除非sh.AddrOfPinnedObject()没有真正指向d ,但那有什么意义呢?

谁能告诉我为什么以上不起作用?

    GCHandle sh = GCHandle.Alloc(d, GCHandleType.Pinned);

这就是你的问题开始的地方。 struct是一种值类型 ,GCHandle.Alloc()只能为引用类型分配句柄。 在垃圾收集堆上分配对象的类型。 而那种使钉扎变得明智的东西。 C#编译器在这里有点太有用了,它会自动发出一个装箱转换来装箱值并使语句有效。 这通常非常好,并且产生了从System.Object派生值类型的错觉。 嘎嘎叫鸭子打字。

问题是,Marshal.Copy()将更新值的盒装副本 不是你的变量。 所以你没有看到它改变。

只有Marshal.PtrToStructure()才能直接更新结构值。 它包含将结构的已发布布局(StructLayout属性)转换为内部布局所需的智能。 这是不一样的,否则是不可发现的。

警告实施细节警报,在.Net的未来版本中可能不是这样。

structs是值类型,并且(通常)存储在堆栈(*)上,而不是堆上。 结构的地址没有意义,因为它们是按值传递的,而不是通过引用传递的。 struct数组是一个引用类型,它是指向堆上内存的指针,因此内存中的地址完全有效。

AddrOfPinnedObject是获取内存固定的对象的地址,而不是结构

此外,Eric Lippert撰写了一系列关于参考类型和价值类型的非常好的博客文章

(*)除非:

1他们是班上的字段
2他们是盒装的
3它们是“捕获的变量”
4它们位于迭代器块中

(nb点3和4是第1点的推论)

这是一个有效的例子:

public static T GetValue<T>(byte[] data, int start) where T : struct
{
    int elementsize = Marshal.SizeOf(typeof(T));

    IntPtr ptr = IntPtr.Zero;

    try
    {
        ptr = Marshal.AllocHGlobal(elementsize);

        Marshal.Copy(data, start, ptr, elementsize);
        return (T)Marshal.PtrToStructure(ptr, typeof(T));
    }
    finally
    {
        if (ptr != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(ptr);
        }
    }
}

但是我会在这里使用显式布局,因为结构对齐

[StructLayout(LayoutKind.Explicit, Size = 3)]
public struct TestStruct
{
    [FieldOffset(0)]
    public byte z;

    [FieldOffset(1)]
    public short y;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM