C#引入了readonly修饰符来表示只读域,const来表示不变常量。顾名思义对只读域不能进行写操作,不变常量不能被修改,这两者到底有什么区别呢?只读域只能在初始化--声明初始化或构造器初始化--的过程中赋值,其他地方不能进行对只读域的赋值操作,否则编译器会报错。只读域可以是实例域也可以是静态域。只读域的类型可以是C#语言的任何类型。但const修饰的常量必须在声明的同时赋值,而且要求编译器能够在编译时期计算出这个确定的值。const修饰的常量为静态变量,不能够为对象所获取。const修饰的值的类型也有限制,它只能为下列类型之一(或能够转换为下列类型的):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, enum类型, 或引用类型。值得注意的是这里的引用类型,由于除去string类型外,所有的类型出去null值以外在编译时期都不能由编译器计算出他们的确切的值,所以我们能够声明为const的引用类型只能为string或值为null的其他引用类型。显然当我们声明一个null的常量时,我们已经失去了声明的意义 --这也可以说是C#设计的尴尬之处!

这就是说,当我们需要一个const的常量时,但它的类型又限制了它不能在编译时期被计算出确定的值来,我们可采取将之声明为static readonly来解决。但两者之间还是有一点细微的差别的。看下面的两个不同的文件:

//file1.cs
//csc /t:library file1.cs
using System;
namespace MyNamespace1
{
public class MyClass1
{
                public static readonly int myField = 10;
        }
}

//file2.cs
//csc /r:file1.dll file2.cs
using System;
namespace MyNamespace2
{
public class MyClass1
{
                public static void Main()
                {
                        Console.WriteLine(MyNamespace1.MyClass1.myField);
                }
        }
}

我们的两个类分属于两个文件file1.cs 和file2.cs,并分开编译。在文件file1.cs内的域myField声明为static readonly时,如果我们由于某种需要改变了myField的值为20,我们只需重新编译文件file1.cs为file1.dll,在执行 file2.exe时我们会得到20。但如果我们将static readonly改变为const后,再改变myField的初始化值时,我们必须重新编译所有引用到file1.dll的文件,否则我们引用的 MyNamespace1.MyClass1.myField将不会如我们所愿而改变。这在大的系统开发过程中尤其需要注意。实际上,如果我们能够理解 const修饰的常量是在编译时便被计算出确定的值,并代换到引用该常量的每一个地方,而readonly时在运行时才确定的量--只是在初始化后我们不希望它的值再改变,我们便能理解C#设计者们的良苦用心,我们才能彻底把握const和readonly的行为!

---------------------

Features:

readonly和const都是用来标识常量的[1]。
const可用于修饰class的field或者一个局部变量(local variable);而readonly仅仅用于修饰class的field。
const常量的值必定在编译时就已明确并且恒定的;而readonly常量却有一点不同,那就是其值可以在运行时编译,当然,它也必须遵守作为常量的约束,那就是值必须恒定不变。
const常量必须在声明的同时对其进行赋值,并且确保该值在编译时可确定并恒定;而readonly常量则可以根据情况选择在声明的同时对其赋予一个编译时确定并恒定的值,或者将其值的初始化工作交给实例构造函数(instant constructor)完成。如:public readonly string m_Now = DateTime.Now.ToString();,m_Now会随着运行时实际情况变化而变化。
const常量属于类级别(class level)而不是实例对象级别(instant object level),并且它不能跟static结合一起使用,该常量的值将由整个类的所有实例对象共同分享(详细论述参见后面的Remark区域)。
readonly常量既可以是类级别也可以是实例对象级别的,这取决于它的声明以及初始化工作怎么实施。readonly可以与static结合使用,用于指定该常量属于类级别,并且把初始化工作交由静态构造函数(static constructor)完成(有关如何把readonly常量声明为类级别或实例对象级别的论述清参见后面的Remark区域) 。
能被const修饰声明为常量的类型必须是以下的基元类型(primitive type):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, float, bool, decimal, string。
object, 数组(Array)和结构(struct)不能被声明为const常量。
一般情况下,引用类型是不能被声明为const常量的,不过有一个例外:string。该引用类型const常量的值可以有两种情况,string或 null。其实,string虽然是引用类型,但是.NET却对它特别处理,这种处理叫做字符串恒定性(immutable),使得string的值具有只读特性。有关字符串恒定性的内容,可以参考《Microsoft .NET框架程序设计(修订版)》。

Examples:

using System;

public class Order
{
    public Order()
    {
        Guid guid = Guid.NewGuid();
        ID = guid.ToString("D");
    }

// 对于每一份订单,其订单序号都是实时确定的常量。
    public readonly string ID;

public override string ToString()
    {
        return "Order ID: " + ID;
    }
}
Explaintion:

如果结合数据库使用,ID field通常都会都会与某个表的主健(primary key)关联起来,如Orders表的OrderID。
数据库的主健通常采用以下三种方式:
自动递增值。你可以通过把DataColumn.AutoIncrement设定为true值来激活自动递增特性。
唯一名称。这个是使用自己定义的算法来生成一个唯一序列号。
GUID(全局唯一标识符)。你可以通过System.Guid结构来生成GUID,如上例。
using System;

class Customer
{
    public Customer(string name, int kind)
    {
        m_Name = name;
        m_Kind = kind;
    }

public const int NORMAL = 0;
    public const int VIP = 1;
    public const int SUPER_VIP = 2;

private string m_Name;
    public string Name
    {
        get { return m_Name; }
    }

private readonly int m_Kind;
    public int Kind
    {
        get { return m_Kind; }
    }

public override string ToString()
    {
        if(m_Kind == SUPER_VIP)
            return "Name: " + m_Name + "[SuperVip]";
        else if(m_Kind == VIP)
            return "Name: " + m_Name + "[Vip]";
        else
            return "Name: " + m_Name + "[Normal]";
    }
}

Remarks:

一般情况下,如果你需要声明的常量是普遍公认的并作为单个使用,例如圆周率,黄金分割比例等。你可以考虑使用const常量,如:public const double PI = 3.1415926;。如果你需要声明常量,不过这个常量会随着实际的运行情况而决定,那么,readonly常量将会是一个不错的选择,例如上面第一个例子的订单号Order.ID。
另外,如果要表示对象内部的默认值的话,而这类值通常是常量性质的,那么也可以考虑const。更多时候我们对源代码进行重构时(使用Replace Magic Number with Symbolic Constant),要去除魔数(Magic Number)的影响都会借助于const的这种特性。
对于readonly和const所修饰的变量究竟是属于类级别的还是实例对象级别的问题,我们先看看如下代码:

使用Visual C#在Main()里面使用IntelliSence插入Constant的相关field的时候,发现ReadonlyInt和 InstantReadonlyInt需要指定Constant的实例对象;而ConstInt和StaticReadonlyInt却要指定 Constant class(参见上面代码)。可见,用const或者static readonly修饰的常量是属于类级别的;而readonly修饰的,无论是直接通过赋值来初始化或者在实例构造函数里初始化,都属于实例对象级别。
一般情况下,如果你需要表达一组相关的编译时确定常量,你可以考虑使用枚举类型(enum),而不是把多个const常量直接嵌入到class中作为 field,不过这两种方式没有绝对的孰优孰劣之分。

using System;

enum CustomerKind
{
    SuperVip,
    Vip,
    Normal
}

class Customer
{
    public Customer(string name, CustomerKind kind)
    {
        m_Name = name;
        m_Kind = kind;
    }

private string m_Name;
    public string Name
    {
        get { return m_Name; }
    }

private CustomerKind m_Kind;
    public CustomerKind Kind
    {
        get { return m_Kind; }
    }

public override string ToString()
    {
        return "Name: " + m_Name + "[" + m_Kind.ToString() + "]";
    }
}

然而,当这种结合使用枚举和条件判断的代码阻碍了你进行更灵活的扩展,并有可能导致日后的维护成本增加,你可以代之以多态,使用Replace Conditional with Polymorphism来对代码进行重构。(有关多态的详细介绍,请参见《今天你多态了吗?》一文。)

Comments:

readonly field准确来说应该翻译成为“只读域”,这里是为了统一翻译用语才将它和const两者所修饰的量都说成“常量”,希望没有引起误会。
------------------------------------------------

C# FAQ: const和static readonly有什么区别?
我们都知道,const和static readonly的确很像:通过类名而不是对象名进行访问,在程序中只读等等。在多数情况下可以混用。
二者本质的区别在于,const的值是在编译期间确定的,因此只能在声明时通过常量表达式指定其值。而static readonly是在运行时计算出其值的,所以还可以通过静态构造函数来赋值。
明白了这个本质区别,我们就不难看出下面的语句中static readonly和const能否互换了:
1. static readonly MyClass myins = new MyClass();
2. static readonly MyClass myins = null;
3. static readonly A = B * 20;
   static readonly B = 10;
4. static readonly int [] constIntArray = new int[] {1, 2, 3};
5. void SomeFunction()
   {
      const int a = 10;
      ...
   }

1:不可以换成const。new操作符是需要执行构造函数的,所以无法在编译期间确定
2:可以换成const。我们也看到,Reference类型的常量(除了String)只能是Null。
3:可以换成const。我们可以在编译期间很明确的说,A等于200。
4:不可以换成const。道理和1是一样的,虽然看起来1,2,3的数组的确就是一个常量。
5:不可以换成readonly,readonly只能用来修饰类的field,不能修饰局部变量,也不能修饰property等其他类成员。

因此,对于那些本质上应该是常量,但是却无法使用const来声明的地方,可以使用static readonly。例如C#规范中给出的例子:

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);static readonly需要注意的一个问题是,对于一个static readonly的Reference类型,只是被限定不能进行赋值(写)操作而已。而对其成员的读写仍然是不受限制的。

public static readonly MyClass myins = new MyClass();

myins.SomeProperty = 10;  //正常
myins = new MyClass();    //出错,该对象是只读的

但是,如果上例中的MyClass不是一个class而是一个struct,那么后面的两个语句就都会出错。

private byte red, green, blue;

public Color(byte r, byte g, byte b)
    {
        red = r;
        green = g;
        blue = b;
    }
}

using System;

namespace ConstantLab
{
    class Program
    {
        static void Main(string[] args)
        {
            Constant c = new Constant(3);
            Console.WriteLine("ConstInt = " + Constant.ConstInt.ToString());
            Console.WriteLine("ReadonlyInt = " + c.ReadonlyInt.ToString());
            Console.WriteLine("InstantReadonlyInt = " + c.InstantReadonlyInt.ToString());
            Console.WriteLine("StaticReadonlyInt = " + Constant.StaticReadonlyInt.ToString());

Console.WriteLine("Press any key to continue");
            Console.ReadLine();
        }
    }

class Constant
    {
        public Constant(int instantReadonlyInt)
        {
            InstantReadonlyInt = instantReadonlyInt;
        }

public const int ConstInt = 0;

public readonly int ReadonlyInt = 1;

public readonly int InstantReadonlyInt;

public static readonly int StaticReadonlyInt = 4;
    }
}

转载于:https://www.cnblogs.com/wwwzzg168/p/3572050.html

C#中const和readonly的区别相关推荐

  1. C# 中const和readonly的区别

    const 的概念就是一个包含不能修改的值的变量. 常数表达式是在编译时可被完全计算的表达式.因此不能从一个变量中提取的值来初始化常量. 如果 const int a = b+1;b是一个变量,显然不 ...

  2. C#中const和readonly有什么区别?

    C#中const和readonly什么区别? 您什么时候可以使用另一个? #1楼 常量成员是在编译时定义的,不能在运行时更改. 使用const关键字将const声明为字段,并且必须在声明const对其 ...

  3. 请叙const与readonly的区别

    请叙const与readonly的区别 a. const 关键字用于修改字段或局部变量的声明.它指定字段或局部变量的值不能被修改.常数声明引入给定类型的一个或多个常数. const 数据成员的声明式必 ...

  4. uniapp 获取到js文件var一个变量怎么获取到这个变量值_浅析Js中const,let,var的区别及作用域...

    理解:let变量的作用域只能在当前函数中 js中const,let,var的区别及作用域_lianzhang861的博客-CSDN博客​blog.csdn.net 全局作用域中,用 const 和 l ...

  5. c#中const与readonly区别

    const表示常量,定义的时候就要初始化:readonly表示只读,定义的时候可以不初始化,可以延迟到构造方法中进行初始化. 以下转载的两篇文章写的很好. 转载 追梦赤子心 的文章:C#基础知识七之c ...

  6. (转)c#中const与readonly区别

    const 的概念就是一个包含不能修改的值的变量. 常数表达式是在编译时可被完全计算的表达式.因此不能从一个变量中提取的值来初始化常量. 如果 const int a = b+1;b是一个变量,显然不 ...

  7. const和readonly内部区别

    const和readonly关键字也是面试中经常考到的问题,通常都是用来表示一个不可变的变量成员,那么具体区别是什么?从用法上说,const只能以inline代码的形式定义,而readonly既可以以 ...

  8. C++ 中 const和define的区别

    来源网址:http://wujiangping.blog.163.com/blog/static/195182011201255115125205/ 请区别用#define命令定义的符号常量和用con ...

  9. C#:const 和readonly的区别

    const字段只能在该字段的声明中初始化:readonly字段可以在声明或者构造函数中初始化.因此,根据所使用的构造函数,readonly字段可能具有不同的值 const字段为编译时常数:readon ...

最新文章

  1. linux mysql 管理(转载)
  2. 趣学python3(30)-字典
  3. 【可视化】seaborn常用的10种数据分析图表
  4. C语言预处理功能——关于字符串化和符号粘贴
  5. 手机屏幕厂家信息软件_警惕假个税手机软件蹭热点,千万别被窃取私人信息
  6. 表情包+外卖+壁纸小程序源码
  7. 相机标定(2)opencv2实现
  8. android必看java_Android开发工程师必看笔试题:Java基础选择题(一)
  9. WaitForMultipleObjects函数有效值分析
  10. 漫谈Google的Native Client(NaCl)技术(二)–技术篇(兼谈LLVM)
  11. 软件开发人员,自身素质应该注意的问题!
  12. ui-sref与$state.go()的使用
  13. 汇编语言伪指令详解(附实例)
  14. 电力电子技术各类整流电路Matlab_simulink仿真分析
  15. 怎么做有效沟通技巧员工培训PPT课件?
  16. mysql+视频文件转成流_详解java调用ffmpeg转换视频格式为flv
  17. 每天学一点英文:Espresso 20210811
  18. sk_buff属性详解
  19. 超详细的canal使用总结
  20. 西北乱跑娃 -- VUE3引入echarts

热门文章

  1. Redis分布锁原理简介和实现过程
  2. 配置配置DruidDataSource
  3. 弹载计算机的上市公司,基于无线通信的弹载计算机系统BIT设计
  4. 使用fio测试磁盘I/O性能
  5. 基于Libevent最小根堆定时器的C++定时器实现
  6. onvif规范的实现:server端Discovery实现,通过OnvifTestTool12.06测试
  7. Go 语言之父详述切片与其他编程语言数组的不同
  8. 深入理解SpringBoot(5)
  9. MQ如何防止消息丢失
  10. mac 安装brew及设置国内镜像