[英]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屬性)轉換為內部布局所需的智能。 這是不一樣的,否則是不可發現的。
這是一個有效的例子:
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.