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));
如图:

C# 如何获取某个类型或类型实例对象的大小的更多相关文章
- block本质探寻五之atuto类型局部实例对象
说明:阅读本文章,请参考之前的block文章加以理解: 一.栈区block分析 //代码 //ARC void test1() { { Person *per = [[Person alloc] in ...
- springboot启动流程(一)构造SpringApplication实例对象
所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 启动入口 本文是springboot启动流程的第一篇,涉及的内容是SpringApplicat ...
- C#动态创建接口的实现实例对象
本文简单介绍如何动态创建接口interface的实现实例对象,包含两个知识点: 1.如何获取接口interface的所有实现实例对象? 2.如何判断实例对象的构造函数是否有参数? 准备工作 首先新建一 ...
- C# 获取与解析枚举类型的 DescriptionAttribute
原文:C# 获取与解析枚举类型的 DescriptionAttribute System.ComponentModel.DescriptionAttribute 这个 Attribute,经常被用来为 ...
- Gson通过借助TypeToken获取泛型参数的类型的方法
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下. 由于Java泛型的实现机制,使 ...
- Gson通过借助TypeToken获取泛型参数的类型的方法(转)
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下. 由于Java泛型的实现机制,使 ...
- java入门---变量类型&类变量&局部变量&实例变量&静态变量
在Java语言中,所有的变量在使用前必须声明.声明变量的基本格式如下: type identifier [ = value][, identifier [= value] ...] ; ...
- SpringBoot27 JDK动态代理详解、获取指定的类类型、动态注册Bean、接口调用框架
1 JDK动态代理详解 静态代理.JDK动态代理.Cglib动态代理的简单实现方式和区别请参见我的另外一篇博文. 1.1 JDK代理的基本步骤 >通过实现InvocationHandler接口来 ...
- struts文件上传,获取文件名和文件类型
struts文件上传,获取文件名和文件类型 Action中还有两个属 性:uploadFileName和uploadContentType,这两个属性分别用于封装上传文件的文件名.文件类型.这是S ...
随机推荐
- jquery与后台相互传递中文参数乱码
前端.后台传递中文参数,乱码的情况: var a="参数乱码"; //编译两次 window.location.href=encodeURI(encodeURI(&q ...
- C/C++代码检视实例
相关文章链接如下: 微软过桥问题与测试人员素养 等价类分法 新解 测试用例设计中的NP难题 90%程序员写不出无BUG的二分查找程序? C/C++代码检视要点 4.1 代码检视 ...
- select框默认样式去除(ie中隐藏默认下拉图标)
html代码 <select class="info-select"> <option selected="selected">1< ...
- PythonCrawl自学日志(2)
一.Scrapy环境的安装 1.配套组件的安装 由于开发环境是在VS2015Community中编码,默认下载的python3.5,系统是windows8.1,为此需要安装的组件有如下列表: 所有的组 ...
- python模块之os和os.path模块
1.os模块os.listdir(dirname) 列出dirname下的目录和文件os.getcwd()函数得到当前工作目录,即当前Python脚本工作的目录路径.os.getenv()和os.pu ...
- poj 2187 Beauty Contest
Beauty Contest 题意:给你一个数据范围在2~5e4范围内的横纵坐标在-1e4~1e4的点,问你任意两点之间的距离的最大值的平方等于多少? 一道卡壳凸包的模板题,也是第一次写计算几何的题, ...
- android apk 反编译
Apk文件结构 apk文件实际是一个zip压缩包,可以通过解压缩工具解开.以下是我们用zip解开helloworld.apk文件后看到的内容.可以看到其结构跟新建立的工程结构有些类似. java代码: ...
- Ubuntu下使用ap-hotspot出现“Another process is already running"问题的解决方案
参考Problem with ap-hotspot 问题描述: This is the message displayed in my terminal screen when I typed sud ...
- C++引用的实质
转自探索c++的底层机制 在看这篇文章之前,请你先要明白一点:那就是c++为我们所提供的各种存取控制仅仅是在编译阶段给我们的限制,也就是说是编译器确保了你在完成任务之前的正确行为,如果你的行为不正确, ...
- [jobdu]数组中出现次数超过一半的数字
找到以后要再扫一遍确认. http://zhedahht.blog.163.com/blog/static/25411174201085114733349/ #include <iostream ...