两种常量类型-readonly和const
C#中有两种常量类型,分别为readonly(运行时常量)与const(编译时常量),本文将就这两种类型的不同特性进行比较并说明各自的适用场景。
工作原理
readonly
为运行时常量(动态常量),程序运行时进行赋值,赋值完成后便无法更改,因此也有人称其为只读变量。
const
为编译时常量(静态常量),程序编译时将对常量值进行解析,并将所有常量引用替换为相应值。
常量可以为数字、布尔值、字符串或 null 引用,不允许在常数声明中使用 static 修饰符,只能在该字段的声明中初始化。
区别可以从静态常量和动态常量的特性来说明:
- const修饰的常量在声明时必须初始化值;readonly修饰的常量可以不初始化值,且可以延迟到构造函数。
- cons修饰的常量在编译期间会被解析,并将常量的值替换成初始化的值;而readonly延迟到运行的时候。
- const修饰的常量注重的是效率;readonly修饰的常量注重灵活。
- const修饰的常量没有内存消耗;readonly因为需要保存常量,所以有内存消耗。
- const只能修饰基元类型、枚举类、或者字符串类型;readonly却没有这个限制。
实例解说
下面声明两个常量:
public static readonly int A = 2; //A为运行时常量
public const int B = 3; //B为编译时常量
下面的表达式:
int C = A + B;
经过编译后与下面的形式等价:
int C = A + 3;
可以看到,其中的const常量B被替换成字面量3,而readonly常量A则保持引用方式。
声明及初始化
readonly常量只能声明为类字段,支持实例类型或静态类型,可以在声明的同时初始化或者在构造函数中进行初始化,初始化完成后便无法更改。
const常量除了可以声明为类字段之外,还可以声明为方法中的局部常量,默认为静态类型(无需用static修饰,否则将导致编译错误),但必须在声明的同时完成初始化。
数据类型支持
由于const常量在编译时将被替换为字面量,使得其取值类型受到了一定限制。const常量只能被赋予数字(整数、浮点数)、字符串以及枚举类型。下面的代码无法通过编译:
public const DateTime D = DateTime.MinValue;
改成readonly就可以正常编译:
public readonly DateTime D = DateTime.MinValue;
可维护性
readonly以引用方式进行工作,某个常量更新后,所有引用该常量的地方均能得到更新后的值。
const的情况要稍稍复杂些,特别是跨程序集调用:
public class Class1
{
public static readonly int A = 2; //A为运行时常量
public const int B = 3; //B为编译时常量
}
public class Class2
{
public static int C = Class1.A + Class1.B; //变量C的值为A、B之和
}
Console.WriteLine(Class2.C); //输出"5"
假设Class1与Class2位于两个不同的程序集,现在更改Class1中的常量值:
public class Class1
{
public static readonly int A = 4; //A为运行时常量
public const int B = 5; //B为编译时常量
}
编译Class1并部署(注意:这时并没有重新编译Class2),再次查看变量C的值:
Console.WriteLine(Class2.C); //输出"7"
结果可能有点出乎意料,让我们来仔细观察变量C的赋值表达式:
public static int C = Class1.A + Class1.B;
编译后与下面的形式等价:
public static int C = Class1.A + 3;
因此不管常量B的值如何变,对最终结果都不会产生影响。虽说重新编译Class2即可解决这个问题,但至少让我们看到了const可能带来的维护问题。
性能比较
const直接以字面量形式参与运算,性能要略高于readonly,但对于一般应用而言,这种性能上的差别可以说是微乎其微。
适用场景
在下面两种情况下:
a.取值永久不变(比如圆周率、一天包含的小时数、地球的半径等)
b.对程序性能要求非常苛刻
可以使用const常量,除此之外的其他情况都应该优先采用readonly常量。
参考:
http://www.cnblogs.com/liujie2272/p/5465255.html
http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/readonly
两种常量类型-readonly和const的更多相关文章
- java List递归排序,传统方式和java8 Stream优化递归,无序的列表按照父级关系进行排序(两种排序类型)
当有一个List列表是无序的,List中的数据有parentid进行关联,通过java排序成两种排序类型: 所用的测试列表最顶级无parentid,若为特殊值,修改下判断方法即可. 第一种排序:按照树 ...
- 列举两种不同类型的Java标识注释,并解释它们之间的区别。
列举两种不同类型的Java标识注释,并解释它们之间的区别.
- ElasticSearch 学习记录之Text keyword 两种基本类型区别
ElasticSearch 系列文章 1 ES 入门之一 安装ElasticSearcha 2 ES 记录之如何创建一个索引映射 3 ElasticSearch 学习记录之Text keyword 两 ...
- Java中的两种异常类型及其区别?
Java中的两种异常类型是什么?他们有什么区别? Throwable包含了错误(Error)和异常(Excetion两类) Exception又包含了运行时异常(RuntimeException, 又 ...
- c++中两种常量方法的比较
[c++]在C++中定义常量的两种方法的比较 常量是定以后,在程序运行中不能被改变的标识符.C++中定义常量可以用#define .const 这两种方法.例如: #define PRICE 10 ...
- Spring的IOC逐层深入——依赖注入的两种实现类型
构造器注入 构造器注入,即通过构造函数完成依赖关系的设定.我们看一下spring的配置文件: <?xml version="1.0" encoding="UTF-8 ...
- 第二节:比较DateTime和DateTimeOffset两种时间类型并介绍Quartz.Net中用到的几类时间形式(定点、四舍五入、倍数、递增)
一. 时间的类型 1. 背景 这里为什么要介绍时间类型呢,明明是定时调度篇,原因是在定时任务中,任务什么时间开始执行,什么时间结束执行,要用到各种各样的时间模式,虽然这不能算是一个复杂的问题,但在正式 ...
- 【SSH进阶之路】Spring的IOC逐层深入——依赖注入的两种实现类型(四)
上篇博文,我们介绍了为什么使用IOC容器,和IOC的设计思想以及IOC容器的优缺点,并且给大家转载了一篇介绍IOC原理的博文,我们这篇主要给大家依赖注入的两种方式,以及他们的优缺点. 我们这篇博文还是 ...
- nodejs的POST两种type类型提交(原生)
POST数据的两种提交格式 application/x-www-form-urlencoded(上传数据中没有文件) multipart/form-data (文件上传) 获取POST数据,post数 ...
随机推荐
- 四种losses
1. Classification losses 每次输入一个样本,对样本进行类别预测,根据预测类别和真实标签得到对应的分类损失. 2. Pairwise losses 每次输入两个样本,数据集包含了 ...
- ubuntu18.04配置nvidia docker和远程连接ssh+远程桌面连接(二)
ubuntu18.04配置nvidia docker和远程连接ssh+远程桌面连接(二) 本教程适用于想要在远程服务器上配置docker图形界面用于深度学习的用户. (二)nvidia docker配 ...
- [置顶网]POWER 9为云与智能打造强大引擎
POWER 9为云与智能打造强大引擎 关键字: 浪潮商用机器 POWER9 至顶网服务器频道 (文/董培欣): 从全球角度看,政治经济波动持续.逆全球化趋势抬头.技术加速变革商业等因素促使企业需要数字 ...
- 在delphi中我用DBGrid选择多条记录,如何一次把选择的多条记录删掉
procedure TForm1.btnDoSumClick(Sender: TObject);var i: Integer;begin if DBGrid1.SelectedRows.Count ...
- ES6学习笔记(四):异步操作
Promise Promise三种状态 pending.resolved.rejected 使用语法 var promis = new Promise(function(resolve,reject) ...
- 自动化运维—Ansible(上)
一:为什么选择Ansible 相对于puppet和saltstack,ansible无需客户端,更轻量级 ansible甚至都不用启动服务,仅仅只是一个工具,可以很轻松的实现分布式扩展 更强的远程命令 ...
- suse11/12关闭防火墙
suse11关闭操作为:service SuSEfirewall2_setup stopservice SuSEfirewall2_init stop 取消开机启动防火墙:chkconfig SuS ...
- Nastya and a Wardrobe CodeForces - 992C(规律)
写一下二叉树 推一下公式就出来了, 注意取模时的输出形式 #include <bits/stdc++.h> #define mem(a, b) memset(a, b, sizeof(a ...
- HGOI20181030 模拟题解
problem:给定一个序列,问你能不能通过一次交换把他弄成有序 sol: 对于0%的数据,满足数列是一个排列,然后我就打了这档分(自己瞎造的!) 对于100%的数据,显然我们先对数列进行排序然后上下 ...
- NOI Linux的安装说明以及使用指南
安装 本人的安装环境为Win10. 1. 首先从官网上下载一个CCF官方提供的Noi linux虚拟机以及安装文档 传送门 2. 然后,安装一个VMware Workstation 14 Pro,这里 ...