.net框架读书笔记---常数和字段、const和readonly的区别

接上一篇.net框架读书笔记---类型成员及其访问限定(二),本节学习常数和字段。

一、常数

  常数是一个表示恒定不变的值的符号,定义一个常数符号时,我们必须能够在编译时确定它的值。通过编译后,编译器将常数的值保存在其所定义模块的元数据内。这意味着常数的类型只能是那些编译器认为的基元类型。(注:因为只有基元类型的数据才能利用文本常数,在编译时直接进行初始化。而非基元类型的数据成员只能在运行时调用构造器来完成初始化。)另一个需要注意的是常数总被认为是类型(而非实例)的一部分,这在常数值恒定不变的含义下很容易理解。

     在C#中,下面的类型被称为基元类型,可以被用来定义常数:bool,char,byte,sbyte,decimal,int16,int32,int64,uint64,single,double,以及string。(注,枚举类型由于本身以基元类型新式存储,故也可以被用来定义常数,虽然它不是基元类型)。

  当使用常数符号时,编译器首先从定义常数的模块的元数据中查找出该符号,直接取出常数的值,然后将之嵌入到编译后的IL代码中。因为常数的值是直接嵌入到代码中的,所以常数的值是直接嵌入到代码中的,所以常数在运行时不再分配任何的内存分配。另外,我们也不能获取常数的地址,或者以引用的方式来传递一个常数。这些约束还意味着常数没有一个良好的跨模块版本特性。也就是说只有当确信一个符号的值永远不会改变时,才应该用常数来定义。

首先将下面的代码编译成DLL程序集:

 

 
  

namespace Com
{
public class Component
{
// 注意:C#不允许为常数制定static关键字
// 因为常数隐含是static
public const int MaxEntriesInList = 600 ;
}
}

引用上面得到的程序集,将下面的代码编译成一个应用程序:

 

 
  
namespace TestCom
{
class Program
{
static void Main( string [] args)
{
Console.WriteLine(Com.Component.MaxEntriesInList);
}
}
}

上面的代码清晰的展示了常数所隐含的版本问题。如果我们把前面DLL程序集中MaxEntriesInList常数值修改为500后并重新编译该DLL程序集,后面的应用程序代码将不会受到任何影响。要获取新的常数值,我们必须重新编译应用程序(调试时按Ctrl+F5和直接按F5就可以看到区别,Ctrl+F5编译加运行,F5,不重新编译,直接运行),如果要求一个模块中的数值能够在运行时(而不是编译时)被另一个模块获取,那么就不应该使用常数。相反,我们应该使用只读字段(关于这个问题还可以查与effective C#关于const和readonly的区别那一章,个人感觉讲的特别的详细)。

二、字段

  字段又称数据成员,它保存着一个值类型的实例、或者一个指向引用类型的引用。CLR支持类型(静态)和实例(非静态)两种字段。对于类型字段,系统在该类型被加载进入一个应用程序域时为其分配动态内存,这通常发生在引用该类型的方法第一次被JIT编译时。对于实例字段,系统在该类型的实例被构建时为其分配动态内存。

  因为字段是以动态内存的形式存储的,因此只能在运行时刻获取它们的值。字段也没有常数的版本问题,另外字段可以是任何类型,没有像常数那么的限制。

  CLR支持只读和读写两种字段。大多数字段都是读写字段,这意味着代码在执行过程中字段可以被多次赋值。但是只读字段只能在构造器中被赋值(构造器在对象初次创建时被执行,且只执行一次,值得注意的是构造器内部只读字段可以被多次赋值。这里所指的是实例只读字段和实例构造器,对于静态只读字段,则只能在静态构造器中赋值,静态构造器在该类型初次被引用时执行)。

  下面是用静态只读字段来解决”常数“的版本问题。新版DLL程序集如下:

 
  
namespace Com
{
public class Component
{
// 类型字段需要static关键字
public static readonly int MaxEntriesInList = 60000 ;
}
}

这是唯一需要修改的地方,Program累无需改变。

  当将MaxEntriesInList值修改为20000时,并重新编译该DLL程序集。当再次执行Program时,输出将变为20000,值得指出的时,Program程序代码并没有被重新编译,仅仅是再次运行了一遍

查看effective C#关于readonly和const总结:

  • readonly为运行时常量,const为编译时常量(上面代码已经证明);
  • 编译时常量被运行时常量快,性能好,但是缺乏灵活性(上面已经证明,编译时常量需要重新编译应用程序);
  • 编译时常量(const)仅限于数值和字符串(基元类型),C#不允许使用new来初始化一个编译时常量;
  • const修饰的常量默认是静态的(类型);
  • readonly修饰的字段可以在构造函数中被修改;
  • 使用const较之使用readonly的唯一好处就是性能

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值