在統計類型或類型實例對象時,出了個異常:
“不能作為非托管結構進行封送處理;無法計算有意義的大小或偏移量。”
后來查了一下,原來,我們創建的struct或是class都是屬於復雜類型的。(糾正一下,如果成員又有復雜類型的,而所占字節,在運行時,會有所變量,在這使用Marhsal.SizeOf也是無效的,只能對非托管資源的一個統計)
如果不對其內部的一些成員布局設置,直接sizeof()或是Marshal.SizeOf(object), Marshal.SizeOf(Type)是會報這個異常的。
所以我們要按需去對成員布局設置一下就可以讓上面的sizeof()或是Marshal.SizeOf(object), Marshal.SizeOf(Type)正常執行。
1、了解數據結構布局
數據結構布局嘛,就肯定先得了解:(悲刷,百度不適合搞代碼格式,還是CNBLOG好)
// 摘要:
// 控制當導出到非托管代碼時對象的布局。
[Serializable]
[ComVisible(true)]
public enum LayoutKind
{
// 摘要:
// 對象的成員按照它們在被導出到非托管內存時出現的順序依次布局。這些成員根據在 System.Runtime.InteropServices.StructLayoutAttribute.Pack
// 中指定的封裝進行布局,並且可以是不連續的。
Sequential = 0,
//
// 摘要:
// 對象的各個成員在非托管內存中的精確位置被顯式控制。每個成員必須使用 System.Runtime.InteropServices.FieldOffsetAttribute
// 指示該字段在類型中的位置。
Explicit = 2,
//
// 摘要:
// 運行庫自動為非托管內存中的對象的成員選擇適當的布局。使用此枚舉成員定義的對象不能在托管代碼的外部公開。嘗試這樣做將引發異常。
Auto = 3,
}
Sequential 有序,可不連續,一般我們用這個。
Explicit 這個比較少用,因為都是對成員在內存塊中的位置在精確的定位的。
Auto 這個不是很了解其上述所說的“適當的布局”,如果用這個來布局,會直接出現我上面所說的異常:
”不能作為非托管結構進行封送處理;無法計算有意義的大小或偏移量。“
2、了解怎么對復雜類型布局(類屬性)
要對復雜類型布局,要用到類的屬性設置Attribute基類或是其派生類都可以。StructLayoutAttribute可以。他是Attribute的派生類
// 摘要:
// StructLayoutAttribute類使用戶可以控制類或結構的數據字段的物理布局。
[ComVisible(true)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
public sealed class StructLayoutAttribute : Attribute
從上述定義描述,可以知道StructLayoutAttribute 就是我們想要的類屬性,"以控制類或結構的數據字段的物理布局"
3、DEMO測試:
第一種:Auto
[StructLayout(LayoutKind.Auto)]
class A
{
public short a = 0;
public int b = 0;
public long c = 0;
}
A a = new A();
int asize = Marshal.SizeOf(a.a);//直接引發異常
int bsize = Marshal.SizeOf(a.b);
int csize = Marshal.SizeOf(a.c);
int allsize = Marshal.SizeOf(a);
MessageBox.Show(string.Format("a.Size : [{0}], b.Size : [{1}], c.Size : [{2}], totale : [{3}]", asize, bsize, csize, allsize));
第二種:Explicit
[StructLayout(LayoutKind.Explicit)]//用到Explicit,必須要對成員的大小或是偏移量,有個精確的設置才成員,汗一下,對每個成員喔,不建議使用這個
class A
{
[FieldOffset(0)]//只能配合布局枚舉項為LayoutKind.Explicit時,才可以使用字段偏量設置
public short a = 0;
[FieldOffset(2)]
public int b = 0;
[FieldOffset(6)]
public long c = 0;
}
A a = new A();
int asize = Marshal.SizeOf(a.a);//如果沒有FieldOffset的成員設置,直接引發異常
int bsize = Marshal.SizeOf(a.b);
int csize = Marshal.SizeOf(a.c);
int allsize = Marshal.SizeOf(a);
MessageBox.Show(string.Format("a.Size : [{0}], b.Size : [{1}], c.Size : [{2}], totale : [{3}]", asize, bsize, csize, allsize));
第三種:Sequential
[StructLayout(LayoutKind.Sequential)]//Sequential有序,可不連續,至於他為啥可以成功,我還想讓大牛指點其內部與sizeof配置使用的原理。
class A
{
public short a = 0;
public int b = 0;
public long c = 0;
}
A a = new A();
int asize = Marshal.SizeOf(a.a);//直接成功
int bsize = Marshal.SizeOf(a.b);
int csize = Marshal.SizeOf(a.c);
int allsize = Marshal.SizeOf(a);
MessageBox.Show(string.Format("a.Size : [{0}], b.Size : [{1}], c.Size : [{2}], totale : [{3}]", asize, bsize, csize, allsize));
如圖: