C# 定义常量 两种实现方法

在C#中定义常量的方式有两种,一种叫做静态常量(Compile-time constant),另一种叫做动态常量(Runtime constant)。前者用“const”来定义,后者用“readonly”来定义。 对于静态常量(Compile-time constant),它的书写方式如下:
public const int MAX_VALUE = 10;
为什么称它为静态常量呢,因为如上声明可以按照如下理解(注意:如下书写是错误的,会出编译错误,这里只是为了方便说明)。
public static const int MAX_VALUE = 10;
用const定义的常量,对于所有类对象而言都是一样的,因此需要像访问静态成员那样去访问const定义的常量,而用对象的成员方式去访问会出变异错误。此外,对于静态常量的访问在编译的时候,是用常量的值去替换常量,例如:
int nValue = MAX_VALUE;
这句在编译之后,和如下这句所产生的中间语言代码是一样的。
int nValue = 10;
不过,在用const来定义常量的时候,在类型上有很多限制。首先,此类型必须属于值类型,同时此类型的初始化不能通过new来完成,因此一些用struct定义的值类型常量也不能用const来定义。
相对于const而言,用readonly来定义常量要灵活的多,它的书写方式如下:
public readonly int MAX_VALUE = 10;
为什么称为动态变量,因为系统要为readonly所定义的常量分配空间,即和类的其他成员一样拥有独立的空间。此外,readonly所定义的常量除了在定义的时候可以设定常量值外,还可以在类的构造函数中进行设定。由于readonly所定义的常量相当于类的成员,因此使用const来定义常量所受到的类型限制,在使用readonly去定义的时候全部消失,即可以用readonly去定义任何类型的常量。 综合上面所述,至于对比两者之间的区别具体如下。

静态常量(Compile-time constant) 动态常量(Runtime constant)
定义 声明的同时要设置常量值。声明的时候可以不需要进行设置常量值,可以在类的构造函数中进行设置。
类型限制 首先类型必须属于值类型范围,且其值不能通过new来进行设置。 没有限制,可以用它定义任何类型的常量。
对于类对象而言 对于所有类的对象而言,常量的值是一样的。 对于类的不同对象而言,常量的值可以是不一样的。
内存消耗 无。 要分配内存,保存常量实体。
综述 性能要略高,无内存开销,但是限制颇多,不灵活。 灵活,方便,但是性能略低,且有内存开销。

对于在定义常量的时候,到底是用const来定义还是readonly来定义,我以前为了追求性能,因此尽量用const来定义。但是在此书中,提到了一个关于使用const会产生潜在的bug。就是在程序中使用DLL类库某个类的静态常量时,如果在类库中修改静态常量的值,其它接口没有发生变化,一般来说,程序调用端是不需要重新编译,直接执行就可以调用新的类库。不过就是在此情况下,会产生潜在的bug。这是由于静态常量在编译的时候,是用它的值去替换常量,因此在调用端的程序也是这样进行替换的。例如:在类库中定义了一个静态常量,如下:
public const int MAX_VALUE = 10;
那么对于程序中调用此静态常量这段代码,在编译后产生的中间语言代码中,是用10来进行替换,即使用静态常量的地方,改为10了。 那么当类库的静态变量发生变化后,例如:
public const int MAX_VALUE = 15;
那么对于调用端程序是可以在没有重新编译的情况下进行运行,不过此时程序的中间语言代码对应于静态变量的值是10,而不是新类库中的15。因此这样产生的不一致,程序会引发潜在的bug。解决此类问题的方法,就是调用端程序在更新类库之后重新编译一下,即生成新的中间语言代码。

对于如上在const定义常量时所存在的潜在bug,在用readonly定义常量时是不会发生的。因为readonly定义的常量类似于类的成员,因此在访问的时候需要根据具体常量地址来访问,从而避免此类bug。
鉴于此,本书建议用readonly来替换const去定义常量。

(0)

相关推荐

  • 解析C#中的常量及如何在C#编程中定义常量

    常量是在编译时已知并在程序的生存期内不发生更改的不可变值.常量使用 const 修饰符进行声明.只有 C# 内置类型(System.Object 除外)可以声明为 const. 用户定义的类型(包括类.结构和数组)不能为 const.请使用 readonly 修饰符创建在运行时初始化一次即不可再更改的类.结构或数组. C# 不支持 const 方法.属性或事件. 可以使用枚举类型为整数内置类型(例如 int.uint.long 等等)定义命名常量. 常量必须在声明时初始化.例如: class C

  • C# 基础入门--常量

    常量,顾名思义,就是"不会改变的量". 我们平时书写的数字(比如12.85).字符(比如'F').字符串(比如"谢谢"),它们都属于"字面常量". 有一些常量既重要又容易出错,比如圆周率π的值为3.1415926......,所以,我们常常会使用自定义常量.如: namespace Test { class Program { static void Main(string[] args) { const double PI = 3.141592

  • C#之CLR内存字符串常量池(string)

    C#中的string是比特殊的类,说引用类型,但不存在堆里面,而且String str=new String("HelloWorld")这样的重装也说没有的. 我们先来看一个方法: class Program { static void Main(string[] args) { String s = "HelloWorld"; Console.WriteLine(s); } } 然后我们用ildasm.exe工具把它生成IL语言来看一看它里面是怎么玩的: .met

  • c# 常量和字段

    它的值是在编译时确定的.编译器将常量保存到程序集的元数据中,所有只能是编译器认识的基元类型作为常量. 常量被看成类的一部分,是看出静态成员. 代码引用一个常量符号,会在定义常量的元数据中查找该符号,提取之,并嵌入代码,生成的IL中是值本身. 在c#中使用的是const关键字. 字段:已一种数据成员,可以容纳任何的数据类型,不仅仅想常量一样只能存储基元类型. CLR支持类型字段和实例字段 类型字段:用于容纳字段数据的动态内存是在类型对象中分配的, 而类对象是在类型加载到一个AppDomain中创建

  • 浅谈C#中的常量、类型推断和作用域

    一.常量常量是其值在使用过程中不会发生变化的变量.在声明和初始化变量时,在变量前面家关键字const,就可以把该变量指定为一个常量: const int a=100;//a的值将不可以改变 常量的特征: 1.常量必须在声明时初始化.指定了其值以后,就不能再修改了.2.常量的值必须能在编译时用于计算.因此不能从一个变量中提取的值来初始化常量.如果需要这么做,应该使用只读字段.3.常量总是静态的,但注意,不必在常量的声明中包含修饰符static.(实际上,不允许)在程序中使用常量至少有3个好处: 1

  • c#只读字段和常量的区别,以及静态构造函数的使用实例

    复制代码 代码如下: using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace ConsoleApplication1{    /// <summary>    /// 作者:it小金    /// 功能:c#只读字段和常量的区别,以及静态构造函数的使用    /// </summary>    class Program    {        stat

  • C#中常量和只读变量的区别小结

    常量和只读变量有以下区别: 1.常量必须在声明时就被初始化,指定了值后就不能修改了.只读字段可以在声明时被初始化,也可以在构造函数中指定初始化的值,在构造以后值就不能修改. 2.常量是静态的,而只读字段可以是静态和动态的 3.Const可以用在字段和局部变量,readonly只可以修饰字段

  • C# 定义常量 两种实现方法

    在C#中定义常量的方式有两种,一种叫做静态常量(Compile-time constant),另一种叫做动态常量(Runtime constant).前者用"const"来定义,后者用"readonly"来定义. 对于静态常量(Compile-time constant),它的书写方式如下: public const int MAX_VALUE = 10; 为什么称它为静态常量呢,因为如上声明可以按照如下理解(注意:如下书写是错误的,会出编译错误,这里只是为了方便说

  • jquery与js函数冲突的两种解决方法

    如果您还有别的要求,想继续使用原先的$(),同时还需要与别的类库不冲突的话,还有两种解决方法 其一: 复制代码 代码如下: jQuery.noConflict(); jQuery(function($) { $("p").click(function() //在函数内继续可以使用jquery类库的$()方法 { alert($(this).text()); }) }) var JsCOM_cr = $("cr"); // 在函数外面,照样可以使用JsCOM.js的$

  • 浅谈生产者消费者模型(Linux系统下的两种实现方法)

    生产者消费者问题是同步问题中的一种常见情况,借用一下维基百科的话 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线程--即所谓的"生产者"和"消费者"--在实际运行时会发生的问题.生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程.与此同时,消费者也在缓冲区消耗这些数据.该问题的关键就

  • JS小球抛物线轨迹运动的两种实现方法详解

    本文实例讲述了JS小球抛物线轨迹运动的两种实现方法.分享给大家供大家参考,具体如下: js实现小球抛物轨迹运动的大致思路: 1.用setInterval()方法,进行间隔性刷新,更新小球位置,以实现动态效果 2.绘制小球和运动区域,运动区域可通过flex布局实现垂直居中 3.用物理公式S(y)=1/2*g*t*t,S(x)=V(x)t来计算路径 现确定V(x)=4m/s,刷新的时间间隔设置为0.1s.原本px和米之间的转换,不同尺寸转换不同,本例采用17寸显示器,大约1px=0.4mm.但浏览器

  • Android开发中画廊视图Gallery的两种使用方法分析

    本文实例讲述了Android开发中画廊视图Gallery的两种使用方法.分享给大家供大家参考,具体如下: 第一种方法: 第一步:设计xml布局文件 代码如下:main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_w

  • thinkphp的钩子的两种配置和两种调用方法

    thinkphp的钩子行为类是一个比较难以理解的问题,网上有很多写thinkphp钩子类的文章,我也是根据网上的文章来设置thinkphp的钩子行为的,但根据这些网上的文章,我在设置的过程中,尝试了十几次都没有成功,不过,我还是没有放弃,最后还是在一边调节细节,一边试验的过程中实现了钩子行为的设置.下面是我个人的设置经验,在这里跟大家分享一下. 个人做了两种设置,都试验成功了,一个简单点,在thinkphp的核心文件中模仿核心行为类添加了另一个行为类,下面是截图: 我的虚拟主机配置文件夹是D:/

  • C语言中栈的两种实现方法

    栈的两种实现方式 通常情况下,栈的实现方式有两种,一种方法是使用指针,而另一种方法则是使用数组.但是在调用程序时,我们没有必要知道具体使用了哪种方法. 一.顺序栈 #include<stdio.h> #include<stdlib.h> #define maxsize 64 //定义栈 typedef struct { int data[maxsize]; int top; }sqstack,*sqslink; //设置栈空 void Clearstack(sqslink s) {

  • R语言常用两种并行方法之snowfall详解

    上一篇博客(R中两种常用并行方法之parallel)中已经介绍了R中常见的一种并行包:parallel,其有着简单便捷等优势,其实缺点也是非常明显,就是很不稳定.很多时候我们将大量的计算任务挂到服务器上进行运行时,更看重的是其稳定性. 这时就要介绍R中的另一个并行利器--snowfall,这也是在平时做模拟时用的最多的一种方法. 针对上篇中的简单例子 首先是一个最简单的并行的例子,这个例子不需要载入任何依赖库.函数.对象等.相对也比较简单: library(snowfall) # 载入snowf

  • C语言杨辉三角两种实现方法

    目录 杨辉三角--C语言实现 方法一:利用二维数组实现 方法二(对方法一的改进):  总结 杨辉三角--C语言实现 杨辉三角: 在屏幕上打印杨辉三角. 1 1 1 1 2 1 1 3 3 1 -- 根据上述例子可知: 1.每一行的第一个和第二个数为1: 2.其余的数为正上方和左边数字之和. 方法一:利用二维数组实现 解题思路: 根据杨辉三角的规律,我们可以定义一个二维数组来实现杨辉三角的打印,其中数字的规律为: data[i][j] = data[i - 1][j] + data[i - 1][

  • MyBatis中的collection两种使用方法及效率比较

    目录 第一种方式,采用select 第二种方式,执行一次sql 比较 collection主要是应对表关系是一对多的情况 查询的时候,用到联表去查询 接下来的小案例包括:市,学校,医院(随便写的),写一个最简单的demo 主要的功能就是查询出所有的市以及对应的市下面所有的学校和医院 实体类:医院 @Data @AllArgsConstructor @NoArgsConstructor public class Hospital { private int id; //医院编号 private i

随机推荐