簡體   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