C# 如何獲取某個類型或類型實例對象的大小


在統計類型或類型實例對象時,出了個異常:

“不能作為非托管結構進行封送處理;無法計算有意義的大小或偏移量。”

 

后來查了一下,原來,我們創建的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));

 

如圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM