C# 如何获取某个类型或类型实例对象的大小

简介: 原文:C# 如何获取某个类型或类型实例对象的大小 在统计类型或类型实例对象时,出了个异常: “不能作为非托管结构进行封送处理;无法计算有意义的大小或偏移量。”   后来查了一下,原来,我们创建的struct或是class都是属于复杂类型的。

原文: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));

 

如图:

目录
相关文章
|
1月前
|
JSON C# 数据格式
【Azure Function】C#独立工作模式下参数类型 ServiceBusReceivedMessage 无法正常工作
Cannot convert input parameter 'message' to type 'Azure.Messaging.ServiceBus.ServiceBusReceivedMessage' from type 'System.String'.
111 73
|
2月前
|
程序员 C# 数据库
C# 比较对象新思路,利用反射技术打造更灵活的比较工具
中途接手的项目,碰到需要在更新对象信息时比较并记录差异的需求,最变态的还有附加要求,怎么办?有没有既能满足需求又能对项目影响最小的方法呢?分享这个我封装的方法,一个利用反射技术打造的更灵活的比较工具
|
4月前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
148 65
|
3月前
|
JSON 程序员 C#
使用 C# 比较两个对象是否相等的7个方法总结
比较对象是编程中的一项基本技能,在实际业务中经常碰到,比如在ERP系统中,企业的信息非常重要,每一次更新,都需要比较记录更新前后企业的信息,直接比较通常只能告诉我们它们是否指向同一个内存地址,那我们应该怎么办呢?分享 7 个方法给你!
|
3月前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
55 3
|
3月前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
91 1
|
4月前
|
C#
C# 可空类型(Nullable)
C# 单问号 ? 与 双问号 ??
80 12
|
3月前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
34 0
|
4月前
|
数据可视化 程序员 C#
C#中windows应用窗体程序的输入输出方法实例
C#中windows应用窗体程序的输入输出方法实例
78 0
|
5月前
|
C# 数据安全/隐私保护
C# 一分钟浅谈:类与对象的概念理解
【9月更文挑战第2天】本文从零开始详细介绍了C#中的类与对象概念。类作为一种自定义数据类型,定义了对象的属性和方法;对象则是类的实例,拥有独立的状态。通过具体代码示例,如定义 `Person` 类及其实例化过程,帮助读者更好地理解和应用这两个核心概念。此外,还总结了常见的问题及解决方法,为编写高质量的面向对象程序奠定基础。
59 2