今天Review时看到自己写的这样一段类似的代码:

internal class TestClass
{private bool _inited = false;private int _count = 0;
}

简单地说就是一个类中的私有字段被显示地赋上了默认值。根据我们惯有的经验,这么做不仅多此一举,而且画蛇添足。因为false和0分别是bool型和int型的默认值,也即是如果我们没有显示赋值,它们仍然会是false和0.那么这样其实会在执行时多走一步,是丑陋的代码。

果真如此吗?

事实上,在某些情况下,上面的代码确实会多执行一次,也即CLR在给所有的字段赋上默认值后,我们的逻辑又会把这些字段赋一遍默认值,而且这个赋值的过程是在构造函数中完成的。但是这个情况有一个大大的前提:Debug模式。

查看Debug模式下编译的TestClass的构造器IL指令,可以看到这里确实生成了为字段赋默认值的指令,部分证实了我们的猜想。

那么相同的代码打开Release模式再编译一遍,再来看看结果有什么不一样的吧。

让我们欣慰的是,C#编译器已经聪明地识别出了这是一段完全多余的代码,并且帮助我们做了优化,在构造函数中并不会对赋了默认值的私有字段做任何操作。在任何情况下,我们发布出去的dll都应该是经过Release编译的,所以之前的担心是完全没有必要的。而且鉴于这么做并没有任何性能的损失,显示地给字段赋初值会让阅读者更容易理解作者的用途,不至于迷惑于“是开发忘记了赋初值还是他确实想这么做?”。

明白了这一点之后我们再来看一个更进一步的:

internal class TestClass
{public TestClass(){_inited = false;_count = 0;}private bool _inited;private int _count;
}
这样一段代码,同样在Release模式下编译。都说直接给字段赋值只是通过构造器赋值的一个语法糖,那么上述代码会否被优化呢?编译器有如此聪明么?
 

很遗憾,看来果然不如我们想象地那般神奇。而且和第一张IL代码图进行比较会发现两个构造器对私有字段初始化的时间点是不一样的,直接赋值的初始化点在调用父类的构造器之前,而在构造器中赋值的初始化点在调用父类的构造器之后。通过这里我们可以大致猜出一个实例的构造顺序,即是先有字段,再调用父类构造器,再调用自身构造器。可以通过如下代码做个简单的验证:

internal class TestClass
{public TestClass(){_inited = false;_count = 0;}private bool _inited = true;private int _count = 1;
}
我们并没有给字段赋上默认值,这样可以强迫编译器生成这一段IL指令。查看它的Release编译的IL指令:
 

结果证明了我们的猜想,其中红圈赋值1的操作是我们直接赋值的IL代码,在调用Object的构造器之前执行。而蓝色方框标出的赋值0的操作是我们构造器中显示赋值的IL代码,在调用Object的构造器之后。

转载于:https://www.cnblogs.com/Tyr-Tian/archive/2011/05/04/2037114.html

编译器对私有字段初始化的优化相关推荐

  1. Java反射 - 私有字段和方法

    尽管普遍认为通过Java Reflection可以访问其他类的私有字段和方法. 这并不困难. 这在单元测试中可以非常方便. 本文将告诉你如何. 访问私有字段 要访问私有字段,您需要调用Class.ge ...

  2. 灵魂拷问:用移位来代替除法运算真的效率高吗?Java 编译器到底有没有做除法优化?

    目录 引入 C++ 编译器对除法的优化 Java 编译器对除法的优化 移位运算对应的字节码 除法操作对应的字节码 查看及分析 JIT 即时编译结果 1.手动编译 OpenJDK 2.编译 hsdis- ...

  3. python-装饰器,类与对象,私有字段,析构,__call__,继承,多继承,接口

    1.装饰器执行流程 装饰器可用于权限管理: 装饰器:将原函数替换为wrapper函数 def outer() @outer --- func1作为参数传入outer() def wrapper() - ...

  4. 编写高质量代码改善C#程序的157个建议——建议133:用camelCasing命名私有字段和局部变量...

    建议133:用camelCasing命名私有字段和局部变量 私有变量和局部变量只对本类型负责,它们在命名方式也采用和开放的属性及字段不同的方法.camelCasing很适合这类命名. camelCas ...

  5. Angular Component 实现类,先执行字段初始化,再调用构造函数

    先执行字段初始化: 再执行构造函数: 更多Jerry的原创文章,尽在:"汪子熙":

  6. spring注入私有字段_Spring字段依赖注入示例

    spring注入私有字段 了解如何编写Spring Field Injection示例 . 字段注入是Spring框架 依赖注入的一种 . 在本教程中,我们将编写几个类,并看一看现场注入工程. 有关S ...

  7. 继承能够访问父类私有字段_在单元测试中访问私有字段

    继承能够访问父类私有字段 首先,让我大声说一下,您需要将代码设计为可测试的,以便通过公共方法测试私有字段. 但是,(" buts"是人们仍在编程而不是计算机本身的原因,所以在这里很 ...

  8. 在单元测试中访问私有字段

    首先,让我大声说一下,您需要将代码设计为可测试的,以便通过公共方法测试私有字段. 但是,(" buts"是人们仍在编程而不是计算机本身的原因,所以在这里很高兴)有时您想要并且应该更 ...

  9. 反射-获取java私有内部类反射类型、私有字段

    获取JAVA私有内部类反射类型 方式一 Class.forName("外部类完整路径$内部私有类类名"); 方式二 通过获取对应私有内部类的字段而获取 完整的类名 Class.fo ...

最新文章

  1. linux网络管理原理,Linux__网络管理(物理层 数据链路层 网络层工作原理)
  2. 都是套路!要毁灭人类、喷马斯克、还获得公民身份的机器人Sophia,真相确是...
  3. python3 Number List 元组 字典 用法区分和总结
  4. mysql为查询结果字段赋默认值
  5. Java文件字节流和字符流FileInputStream,FileOutputStream,FileReader,FileWriter
  6. P1967,ssl2267-货车运输【树上倍增LCA,最小生成树变形kruskal】
  7. awk 中 {print $1} 什么意思
  8. 后端用的nodejs怎么打包_你怎么也想象不到,平板玻璃、玻璃瓶这些竟可以用PET塑钢带打包!...
  9. 枚举类中的valueOf用法
  10. HtmlEditor在线编辑器V3.0提供
  11. Excel生成随机32、36位ID
  12. websocket协议详解
  13. php九宫格图片合成,多宫格图片合成
  14. 关于微信小程序本机调试可以运行,真机无法运行的问题
  15. 2023中国(上海)国际大豆食品加工及设备展览会
  16. Java 8 的发展
  17. html仿照QQ发说说功能flask,python-flask写扣扣邮箱发送邮件
  18. TCMalloc 安装和使用
  19. 基于ADI-DSP-1452外挂flash模拟声浪功能调试
  20. r语言 figure margins too large

热门文章

  1. golang备份和恢复
  2. redis之zskiplist
  3. ip(IP)地址详解!
  4. 解决浏览器保存密码自动填充问题
  5. Linux查看所有用户和组信息
  6. 数字采购:企业互联网新引擎
  7. Linux性能相关工具
  8. js中的arguments
  9. 关于rc.local启动程序
  10. Django Localization 之language file