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的更多相关文章

  1. java List递归排序,传统方式和java8 Stream优化递归,无序的列表按照父级关系进行排序(两种排序类型)

    当有一个List列表是无序的,List中的数据有parentid进行关联,通过java排序成两种排序类型: 所用的测试列表最顶级无parentid,若为特殊值,修改下判断方法即可. 第一种排序:按照树 ...

  2. 列举两种不同类型的Java标识注释,并解释它们之间的区别。

    列举两种不同类型的Java标识注释,并解释它们之间的区别.

  3. ElasticSearch 学习记录之Text keyword 两种基本类型区别

    ElasticSearch 系列文章 1 ES 入门之一 安装ElasticSearcha 2 ES 记录之如何创建一个索引映射 3 ElasticSearch 学习记录之Text keyword 两 ...

  4. Java中的两种异常类型及其区别?

    Java中的两种异常类型是什么?他们有什么区别? Throwable包含了错误(Error)和异常(Excetion两类) Exception又包含了运行时异常(RuntimeException, 又 ...

  5. c++中两种常量方法的比较

    [c++]在C++中定义常量的两种方法的比较   常量是定以后,在程序运行中不能被改变的标识符.C++中定义常量可以用#define .const 这两种方法.例如: #define PRICE 10 ...

  6. Spring的IOC逐层深入——依赖注入的两种实现类型

    构造器注入 构造器注入,即通过构造函数完成依赖关系的设定.我们看一下spring的配置文件: <?xml version="1.0" encoding="UTF-8 ...

  7. 第二节:比较DateTime和DateTimeOffset两种时间类型并介绍Quartz.Net中用到的几类时间形式(定点、四舍五入、倍数、递增)

    一. 时间的类型 1. 背景 这里为什么要介绍时间类型呢,明明是定时调度篇,原因是在定时任务中,任务什么时间开始执行,什么时间结束执行,要用到各种各样的时间模式,虽然这不能算是一个复杂的问题,但在正式 ...

  8. 【SSH进阶之路】Spring的IOC逐层深入——依赖注入的两种实现类型(四)

    上篇博文,我们介绍了为什么使用IOC容器,和IOC的设计思想以及IOC容器的优缺点,并且给大家转载了一篇介绍IOC原理的博文,我们这篇主要给大家依赖注入的两种方式,以及他们的优缺点. 我们这篇博文还是 ...

  9. nodejs的POST两种type类型提交(原生)

    POST数据的两种提交格式 application/x-www-form-urlencoded(上传数据中没有文件) multipart/form-data (文件上传) 获取POST数据,post数 ...

随机推荐

  1. Cisco Packet Tracer 交换机 2950-24 配置

    大步骤1:设置交换机名字.特权模式口令.本地管理口令.远程登入口令  Switch>en   进入特权模式 Switch#conf t    进去全局配置模式 Enter configurati ...

  2. 使用ejs模板引擎

    let express = require('express'); let fs = require('fs'); let ejs = require('ejs'); let app = expres ...

  3. Linux命令(二) 复制文件 cp

    cp命令用来复制文件或目录,当复制多个文件时,目标文件参数必须为已经存在的目录,否则将出现错误. cp命令默认不能复制目录,复制目录必须使用 -R 选项.cp命令具备了 ln命令的功能. 命令格式: ...

  4. KSOA单据保护表中Clientid解析为mac和ip

    SELECT DISTINCT a.*,ISNULL(c.client_net_address,'') AS client_net_address FROM ( SELECT * ,),,) ) ), ...

  5. windows文件共享 防火墙规则设置

    防火墙入站规则.完成以下两项设置即可. 设置一 操作:允许连接协议类型:UDP本地端口:137, 138远程端口:所有端口 设置二 操作:允许连接协议类型:TCP本地端口:139, 445远程端口:所 ...

  6. java 强制转换之降级

    大空间的数据类型向小空间的数据类型去转换. 语法:(目标数据类型)变量名 当大空间数据类型转换给小空间时且超过小空间的容量时,编译不会出错,但是会丢失精度 例如 int a = 128 抓换byte ...

  7. luogu3778/bzoj4898 商旅 (floyd+分数规划+spfa)

    首先floyd求出来每两点间的最短距离,然后再求出来从某点买再到某点卖的最大收益 问题就变成了找到一个和的比值最大的环 所以做分数规划,二分出来那个答案r,把边权变成w[i]-r*l[i],再做spf ...

  8. CF1096D Easy Problem(DP)

    貌似最近刷了好多的CF题…… 题目链接:CF原网 洛谷 题目大意:有一个长度为 $n$ 的字符串 $s$,删除第 $i$ 个字符需要代价 $a_i$.问使得 $s$ 不含有子序列(不是子串)" ...

  9. 解题:九省联考2018 秘密袭击CoaT

    题面 按照*Miracle*的话来说,网上又多了一篇n^3暴力的题解 可能是因为很多猫题虽然很好,但是写正解性价比比较低? 直接做不可做,转化为统计贡献:$O(n)$枚举每个权值,直接统计第k大大于等 ...

  10. Json对象和Json字符串的区别

    说白了,字符串都是带引号的. 尤其是在使用springmvc的时候,后台@RequestBody接受的是一个json格式的字符串,一定是一个字符串.  参考这个博客还可以: https://blog. ...