1. const和readonly的值一旦初始化则都不再可以改写;
  2. const只能在声明时初始化;readonly既可以在声明时初始化也可以在构造器中初始化;
  3. const隐含static,不可以再写static const;readonly则不默认static,如需要可以写static readonly;
  4. const是编译期静态解析的常量(因此其表达式必须在编译时就可以求值);readonly则是运行期动态解析的常量;
  5. const既可用来修饰类中的成员,也可修饰函数体内的局部变量;readonly只可以用于修饰类中的成员

前面是我从网上摘录的,文字太多,懒得自己再总结和打字了.

注意,第四点尤为重要,我用以下代码来说明和验证:

1.建立文本文件,然后改成.cs文件-lib.cs:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace ConstReadonly_Base
  6. {
  7. public class Test
  8. {
  9. public const double PI = 3.14;
  10. public static readonly double pi = 3.14;
  11. }
  12. }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConstReadonly_Base
{
public class Test
{
public const double PI = 3.14;
public static readonly double pi = 3.14;
}
}

2.在命令行中输入: csc /t:library lib.cs,就会生成一个lib.dll文件.
3.建立文本文件,然后改成.cs文件-demo.cs:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace ConstReadonly_Demo
  6. {
  7. class Program
  8. {
  9. static void Main(string[] args)
  10. {
  11. Console.WriteLine(ConstReadonly_Base.Test.PI);
  12. Console.WriteLine(ConstReadonly_Base.Test.pi);
  13. Console.ReadKey();
  14. }
  15. }
  16. }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConstReadonly_Demo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(ConstReadonly_Base.Test.PI);
Console.WriteLine(ConstReadonly_Base.Test.pi);
Console.ReadKey();
}
}
}

4.在命令行中输入: csc /r:lib.dll demo.cs,也就会生成一个demo.exe文件.
双击,结果如下:
3.14
3.14
5.更改lib.cs为:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace ConstReadonly_Base
  6. {
  7. public class Test
  8. {
  9. public const double PI = 3.1415;
  10. public static readonly double pi = 3.1415;
  11. }
  12. }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConstReadonly_Base
{
public class Test
{
public const double PI = 3.1415;
public static readonly double pi = 3.1415;
}
}

6.再次双击demo.exe文件,结果却如下:
3.14
3.1415
(注: 直接双击demo.exe是直接运行,不再编译,上结果也就是运行期结束的结果,相当于跳过了编译)
 
原因是什么呢?请听我慢慢道来.
用ILDasm工具(这里假定你会用),选择lib.dll,内容如下:
双击PI段:
内容为
  1. .field public static literal float64 PI = float64(3.1415000000000002)

.field public static literal float64 PI = float64(3.1415000000000002)

双击pi段:
内容为
  1. .field public static initonly float64 pi

.field public static initonly float64 pi

明显lib.cs被编译成元数据和IL汇编时,PI直接被替换成float64(3.1415000000000002)

而.cctor: void()静态构造函数中,

  1. .method private hidebysig specialname rtspecialname static
  2. void  .cctor() cil managed
  3. {
  4. // Code size       15 (0xf)
  5. .maxstack  8
  6. IL_0000:  ldc.r8     3.1415000000000002
  7. IL_0009:  stsfld     float64 ConstReadonly_Base.Test::pi
  8. IL_000e:  ret
  9. } // end of method Test::.cctor

.method private hidebysig specialname rtspecialname static
void .cctor() cil managed
{
// Code size 15 (0xf)
.maxstack 8
IL_0000: ldc.r8 3.1415000000000002
IL_0009: stsfld float64 ConstReadonly_Base.Test::pi
IL_000e: ret
} // end of method Test::.cctor

pi是动态分配内存的,直到运行时才调用静态构造函数来初始化pi.

如果这时你还是不太明白,让我们接下去看:

用ILDasm工具,选择demo.exe,内容如下:

我们来看看Main函数中我们到底做了些什么:

  1. .method private hidebysig static void  Main(string[] args) cil managed
  2. {
  3. .entrypoint
  4. // Code size       34 (0x22)
  5. .maxstack  8
  6. IL_0000:  nop
  7. IL_0001:  ldc.r8     3.1400000000000001
  8. IL_000a:  call       void [mscorlib]System.Console::WriteLine(float64)
  9. IL_000f:  nop
  10. IL_0010:  ldsfld     float64 ['ConstReadonly-Base']ConstReadonly_Base.Test::pi
  11. IL_0015:  call       void [mscorlib]System.Console::WriteLine(float64)
  12. IL_001a:  nop
  13. IL_001b:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  14. IL_0020:  pop
  15. IL_0021:  ret
  16. } // end of method Program::Main

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 34 (0x22)
.maxstack 8
IL_0000: nop
IL_0001: ldc.r8 3.1400000000000001
IL_000a: call void [mscorlib]System.Console::WriteLine(float64)
IL_000f: nop
IL_0010: ldsfld float64 ['ConstReadonly-Base']ConstReadonly_Base.Test::pi
IL_0015: call void [mscorlib]System.Console::WriteLine(float64)
IL_001a: nop
IL_001b: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_0020: pop
IL_0021: ret
} // end of method Program::Main

WriteLine()打印PI时,

  1. IL_0001:  ldc.r8     3.1400000000000001
  2. IL_000a:  call       void [mscorlib]System.Console::WriteLine(float64)

IL_0001: ldc.r8 3.1400000000000001
IL_000a: call void [mscorlib]System.Console::WriteLine(float64)

这说明编译时,PI被编译成一个常量.

WriteLine()打印pi时,

  1. IL_0010:  ldsfld     float64 ['ConstReadonly-Base']ConstReadonly_Base.Test::pi

IL_0010: ldsfld float64 ['ConstReadonly-Base']ConstReadonly_Base.Test::pi

这说明编译时,pi被编译成调用ConstReadonly_Base.Test::pi,可见pi量是动态分配和调用的.

最新文章

  1. CSS3盒模型display:box;box-flex:3;
  2. Here String 中不该进行分词
  3. 如何通过JQuery将DIV的滚动条滚动到指定的位置
  4. MAHOUT_LOCAL is not set; adding HADOOP_CONF_DIR to classpath.
  5. 电脑不能浏览网页but能登录qq,解决方案总结
  6. HTML 几种特别分割线特效
  7. linux 多线程基础3
  8. Git for Windows 工具下载及配置
  9. Asp.NET开启一个线程,不停的执行
  10. 【问题解决记录】Error: Cannot find module '@ionic/app-scripts'
  11. git和github新手安装使用教程(三步入门)
  12. SpringCloud学习笔记(7)——Sleuth
  13. 通过java把excel内容上传到mysql
  14. Maven安装教程详解
  15. 解决js复制在安卓和ios兼容问题
  16. wx 参数传值
  17. Entity framework中LINQ的使用
  18. sql server导入excel数据
  19. node模块加载机制。
  20. linux常用命令:head 命令

热门文章

  1. JAX-WS(JWS)发布WebService
  2. 数组MARSHALLING z
  3. linux统计文件夹某一些文件的大小总和
  4. UVa10635 - Prince and Princess(LCS转LIS)
  5. AJAX中的dataType(数据格式)-text、json
  6. js showModalDialog打开新的页面给原页面传值问题
  7. RSA客户端js加密服务器C#解密(含源码)
  8. AWS s3 python sdk code examples
  9. GNU LIBC源代码学习之strcmp
  10. Emmet最全提示说明