编写高质量代码的50条黄金守则-Day 02(首选readonly而不是const),本文由比特飞原创发布,转载务必在文章开头附带链接:https://www.byteflying.com/archives/6549

该系列文章由比特飞原创发布,计划用半年时间写完全50篇文章,为大家提供编写高质量代码的一般准则。

1、概述

众所周知,.net 包含 2 种类型的常量,运行时常量和编译时常量,它们的表现行为不同,使用不当,会使你陷入困境。虽然编译时常量在执行上速度略快,但我依然强烈建议大家使用运行时常量(readonly),而不是编译时常量(const)。在继续深入了解之前,我们先要知道 .net 中两种常量各自的特点。

2、.net中两种常量的基本特点

我们看看以下代码片段:

两种常量的代码片段

我们很容易总结出它们各自的特点:

1、运行时常量 readonly 要么在定义的时候赋初始值,要么在构造函数中赋初始值;

2、编译时常量 const 必须在定义的时候赋初始值。

那我为什么建议大家使用运行时常量呢?因为编译时常量可能会使你已发行程序的表现的和你测试时不同,这是为什么呢?为了清楚的了解个中原委,我们要明白编译器为运行时常量和编译时常量都做了什么?

3、编译器为readonly和const关键字做了什么?

使用readonly修饰的常量为运行时常量,使用const修饰的常量为编译时常量,我们先来看两段示例代码:

public static readonly int ViewCount1 = ;
public const int ViewCount2 = ;

我们再来看一下两段代码的IL:

使用 DnSpy 解密的 IL 1

使用 DnSpy 解密的 IL 2

DnSpy 的反编译结果

从上面的反编译结果,可以明显的看出 const 为编译时常量,在编译期间已经被写到IL中。而 readonly 为运行时常量。Microsoft 技术支持文档中相关 IL 的解释也可以印证这一点。

Microsoft 技术支持文档中 ldsfld 的解释

Microsoft 技术支持文档中 Ldc_I4_S 的解释

当然,对于这个案例,输出的结果是一致的:

ViewCount1 和 ViewCount2 的输出结果

于是,我们得到以下重要结论:

1、const 和 readonly 在初始化一次后,不能再赋值;

2、const 在编译时被编译器所替换,而 readonly 在编译时只做校验,不作替换处理,运行时表现如同一般变量。

3、const 在 .net 中只能用于 数值型、字符型和 null,没有例外。

我们再看一个简单的示例:

public const int Birthday= ;
if(DateTime.UtcNow.Year == )

if(DateTime.UtcNow.Year == Birthday)

由我们之前的分析可以得知,它们是完全相同的。然而,并不是所有的情况下,你都能得到你所期望的结果,这又是为什么呢?

4、运行时所给出的结果,并不是你所期望的结果

某些情况下,运行时给出的结果与你所期望的结果大相径庭。现在我们有以下场景,你有一个已交付的软件,软件包含一个可执行主程序 EffectiveCoding02.exe ,一个被主程序所引用的类库 EffectiveCoding02.dll,主程序中包含以下代码:

public class SomeClass{

public static readonly int StartValue = ;

public const int EndValue = ;

}

类库中包含以下代码:

for(var i = SomeClass.StartValue; i < SomeClass.EndValue; i++){

console.WriteLine($"value = {i}");

}

当初次交付程序给客户的时候,以上代码完全按照你的预期运行。后来由于软件迭代,你修改了主程序:

public class SomeClass{

public static readonly int StartValue = ;

public const int EndValue = ;

}

重新编译后,因为你只更改了这个主程序,所以你将这个主程序交付给客户,然而你却得不到任何输出内容,程序没有按照你所预期的那样工作,于是你会说出那句开发人员的至理名言,“我这里是正常的啊!”。

产生这个问题的原因在于,由于编译时常量 const 是在编译时被编译器所替换的,所以虽然你进行了编译操作,然而用户计算机中的类库由于没有被编译器重新编译,所以用户计算机中的类库中的 EndValue 还是上一次编译时的结果,即105。然而运行时常量却以正常的方式运作,所以它的值变成了110,自然,你得不到任何的输出结果。因为循环初始值大于结束值。

5、总结

1、运行时常量 readonly 要么在定义的时候赋初始值,要么在构造函数中赋初始值;

2、编译时常量 const 必须在定义的时候赋初始值;

3、const 和 readonly 在初始化一次后,不能再赋值;

4、const 在编译时被编译器所替换,而 readonly 在编译时只做校验,不作替换处理,运行时表现如同一般变量;

5、const 在 .net 中只能用于 数值型、字符型和 null,没有例外;

6、尽量使用 readonly 常量,避免遇到已发行软件无法按预期运行的问题。

开发人员应牢记以上开发守则,否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你、唾弃你。

该系列文章由比特飞原创发布,计划用半年时间写完全50篇文章,为大家提供编写高质量代码的一般准则。

本文由 比特飞 原创发布,欢迎大家踊跃转载。

转载请注明本文地址:https://www.byteflying.com/archives/6549

编写高质量代码的50条黄金守则-Day 02(首选readonly而不是const)的更多相关文章

  1. 编写高质量代码的30条黄金守则-Day 01(首选隐式类型转换)

    编写高质量代码的30条黄金守则-Day 01(首选隐式类型转换),本文由比特飞原创发布,转载务必在文章开头附带链接:https://www.byteflying.com/archives/6455 该 ...

  2. 编写高质量代码改善C#程序的157个建议——建议50:在Dispose模式中应区别对待托管资源和非托管资源

    建议50:在Dispose模式中应区别对待托管资源和非托管资源 真正资源释放代码的那个虚方法是带一个bool参数的,带这个参数,是因为我们在资源释放时要区别对待托管资源和非托管资源. 提供给调用者调用 ...

  3. 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)

    编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...

  4. 编写高质量代码改善C#程序的157个建议——建议28:理解延迟求值和主动求值之间的区别

    建议28:理解延迟求值和主动求值之间的区别 要理解延迟求值(lazy evaluation)和主动求值(eager evaluation),先看个例子: List<, , , , , , , , ...

  5. Github即将破百万的PDF:编写高质量代码改善JAVA程序的151个建议

    在通往"Java技术殿堂"的路上,本书将为你指点迷津!内容全部由Java编码的最佳 实践组成,从语法.程序设计和架构.工具和框架.编码风格和编程思想等五大方面,对 Java程序员遇 ...

  6. 《编写高质量代码--Web前端开发修炼之道》读书笔记

    前言 这两周参加公司的新项目,采用封闭式开发(项目成员在会议室里开发),晚上加班到很晚,所以没时间和精力写原创博客了,今天就分享下这篇<编写高质量代码--Web前端开发修炼之道>读书笔记吧 ...

  7. (第一章)改善JavaScript,编写高质量代码。

    根据<编写高质量代码改善JavaScript程序的188个建议>这本书,来记录我目前所了解的建议方式. 建议1:警惕Unicode乱码 根据ECMA标准规定JavaScript语言可以使用 ...

  8. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  9. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

随机推荐

  1. STL源码剖析:仿函数

    仿函数就是函数对象 函数对象: 重载了operator()的类对象 使用起来和普通函数一致,所以称为函数对象或是仿函数 STL中对于仿函数的参数进行了特殊处理,定义了两个特殊类,类里面只有类型定义 一 ...

  2. 循序渐进nginx(二):反向代理、负载均衡、缓存服务、静态资源访问

    目录 反向代理 使用 1.创建代理目标服务端: 2.配置nginx反向代理目标服务端: 3.测试使用: 负载均衡 使用 1.准备服务端 2.修改nginx配置 3.测试 负载均衡策略 负载均衡的额外参 ...

  3. O、Θ、Ω、o、ω,别再傻傻分不清了!

    前言 本篇文章收录于专辑:http://dwz.win/HjK,点击解锁更多数据结构与算法的知识. 你好,我是彤哥,一个每天爬二十六层楼还不忘读源码的硬核男人. 前面几节,我们一起学习了算法的复杂度如 ...

  4. HTML学习汇总

    HTML学习大汇总 (1)HTML概述 Html(超文本标记语言): 用文字来描述的标签语言,用文字来描述网页的一种语言. HTML是 HyperText Mark-up Language 的首字母简 ...

  5. MongoDB副本集部署

    mongodb 副本集搭建 环境192.168.1.191   master192.168.1.192   slave,arbiterOS: ubuntu14.04mongodb: mongodb-l ...

  6. 利用Python的装饰器一键开启多线程

    记录一下自己写的烂代码 import time import threading def WithThread(obj): """这是一个开启线程的装饰器"&q ...

  7. Web压测工具之Webbench和http_load

    Webbench简介 是知名的网站压力测试工具,能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况. webbench的标准测试可以向我们展示服务器的两项内容:每秒钟相应请求数和每 ...

  8. PHP shuffle() 函数

    实例 把数组中的元素按随机顺序重新排列: <?php$my_array = array("red","green","blue",&q ...

  9. PHP curl_setopt函数

    (PHP 4 >= 4.0.2, PHP 5) curl_setopt — 设置一个cURL传输选项. 说明 bool curl_setopt ( resource $ch , int $opt ...

  10. 转载——完整的ASCII码表

    完整的ASCII码表,转载自下面的博主: http://www.cnblogs.com/xmxu/archive/2012/07/10/2584032.html