Last time when I was asked what is the diff between Readonly and ConstI was really ashamed that I said don’t know on explaining the exact difference between this two simple key word…„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
过后,特意研究了下这两个关键字究竟有何不同:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
首先,从CLI中对CTSType的规定说起。在第四版本的ECMA-355CLI标准中,规定的对于每一个Type,都可以包含很多成员。所有的成员(members),一共可以有三种:第一种叫做fields,它是定义的和这个类型相关的存储单元。第二中成员类型就是我们熟悉的方法(Method)。第三中,叫做nested type。也就是嵌套类型,对于每一个type里面,都可以包含对于别的type的声明和使用。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
对于所有的成员,又可以分为两种:per-type memberper-instance member。顾名思义,前一种,是对于每一个type只有一个的成员,譬如static修饰的field。后一种,是对于每一个运行时候的实例,都保持一个不同的实现版本。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
对于其他的类型的成员,包括我们熟知的PropertiesEvents之类,这些反编译成为IL语言之后可以看到,全部直接的,或者是间接的转换成为了方法。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
有的时候,我们需要一个field在它的整个生命周期里面,它所包含的这个值是不改变的。这个时候,根据这个变量被赋值的不同的情况,CLR为提供了两种技术来实现这种要求:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
第一种,field里面包含的值,可以在编译的时候被计算出来。就是const关键字声明的变量。这种方法的实现效率是最高的。这个值,是作为一个字面上的固定的值,保存在包含这个typemodule文件的metadata里面。Const定义的这个值,可以是一个表达式,但是这个表达式的结果,必须是编译的时候可以计算出来的。这样,在编译的时候,就可以植入到其余的指令里面去。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Const定义的field,必须在定义的时候,就给初始化了,而且,一旦初始化了之后,就不能再改变它的值。同时,不能声明一个constfieldstatic,因为,const定义的field就表明这个field是一个static的。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
任何对const定义的常量的修改,都会抛出一个编译时错误。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
我们可以把const修饰的field,归类到memberper-type member里面去。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
第二种,是被readonly修饰的fieldReadonly修饰的常量,可能是因为,有的时候,我们需要一些field,它的值是不应该改变的,但是,在运行之前,是不知道这个值的,这个时候,就可以用readonly来修饰这个field„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
这个readonly修饰的field,就为常量这个名词提供了另外一种灵活得多的解决方案了。首先,它的值,是可以在运行的时候,根据别的变量动态计算出来的,而const修饰的常量的值就不能这样了。同时,不同于const,它是一个per-instance member。也就是说,对于每一个实例,它都可以保存一个不同的实现版本,而const就不行了。对于某一个type的所有的实现实例,const定义的field,只能有一个不变的值。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
写到这里,从原理的角度已经阐述的比较清楚了,接着用一个实例来分析下:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
class Program
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
public const int conField=122*1119;
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
public readonly int roField;
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
private int _property;
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
public int Property
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
get
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
return _property;
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
set
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
_property = value;
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
static void Main(string[] args)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
(new Program()).Method();
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Diassemble之后,得到下面的显示结果:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.namespace TestConcoleApp„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.class private auto ansi beforefieldinit Program
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
extends [mscorlib]System.Object
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
//
这里可以看到,一个const定义的一个field,是literal,并且被static关键字来修饰。同时,在编译的时候,就计算得到了这个field的值。
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.field public static literal int32 conField = int32(136518)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
//readonly
关键字修饰的field,只是被用initonly来修饰,per-instance类型。
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.field public initonly int32 roField
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.field private int32 _property
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
//
在程序的属性里面定义的get关键字,最终在这里被转换成为了一个方法来处理。
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.method public hidebysig specialname instance int32 get_Property() cil managed
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.maxstack 1
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.locals init (int32)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0000:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
nop„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0001:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ldarg.0„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0002:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ldfld„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
int32 TestConcoleApp.Program::_property
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0007:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
stloc.0„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0008:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
br.s„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_000a
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_000a:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ldloc.0„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_000b:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ret„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
//
对上面的一个Propertyset动作,最终在这里转化成为了一个方法
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.method public hidebysig specialname instance void set_Property(int32 'value') cil managed
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.maxstack 8
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
      „hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0000:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
nop„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0001:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ldarg.0„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0002:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ldarg.1„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0003:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
stfld„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
int32 TestConcoleApp.Program::_property
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0008:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ret„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.method private hidebysig static void Main(string[] args) cil managed
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.entrypoint
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.maxstack 8
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
      „hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0000:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
nop„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0001:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
newobj„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
instance void TestConcoleApp.Program::.ctor()
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_000b:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
nop„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_000c:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ret„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.maxstack 8
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
      „hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0000:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ldarg.0„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0001:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
call„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
instance void [mscorlib]System.Object::.ctor()
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
IL_0006:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
ret„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
//
这里用property来表示一个属性,实际上是转换成为了两个方法来操作一个private修饰的field
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.property instance int32 Property()
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
{
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.get instance int32 TestConcoleApp.Program:[img]editor/images/smilies/default/24.gif[/img]„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
.set instance void TestConcoleApp.Program::set_Property(int32)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
}„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
再看了readonlyconst被编译成为IL的代码之后,对这两个关键字到底是如何运作,有什么区别和相同的地方,又有了进一步的确认和了解。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
后记:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
其实,我还想验证一下,public const int conField=122*1119;这一句中122*1119的结果,在作为一个module的时候,是计算好了保存在一个扩展了的DotNet下的PE文件的Metadata里面,然后在验证一下,运行的时候,一个type有多个实例,而const定义的field只有一个的。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
不过动用了一大批调试工具和托管模块结构查看工具,把PE格式文件里面的元数据表狠狠的都刨了一遍,也没找到这个值。在这个文件执行的时候,windbg attach到这个进程,把这个模块在的内存刨了一个遍,还是没找到这个常量具体的location….郁闷坏了„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
先就整理到这里吧,改天好好的分析下PE文件格式里面的元数据表和托管进程的内存布局。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
     
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
后记补记:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
今天,又把metadata的几种表结构的reference看了看,把上面生成的那个托管模块里里外外又刨了一次,用dumpbin+ildasm,在查看元数据表的时候,终于找到了上面用readonlyconst定义的两个字段在元数据里面的表示:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Field #1 (04000001)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
-------------------------------------------------------
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Field Name: conField (04000001)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Flags„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
: [Public] [Static] [Literal] [HasDefault]„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
(00008056)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
DefltValue: (I4) 136518
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
CallCnvntn: [FIELD]
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Field type:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
I4
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Field #2 (04000002)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
-------------------------------------------------------
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Field Name: roField (04000002)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Flags„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
: [Public] [InitOnly]„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
(00000026)
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
CallCnvntn: [FIELD]
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
Field type:„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
I4
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
可以看到,在编译成为托管模块的时候,这个const定义的变量就被计算了出来,把值136518已经保存到了托管PE文件的元数据表里面。并且,还有staticliteralhasdefault这几个关键字来修饰。而readonly修饰的field,只有一个initonly来修饰。„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
      到这里,终于给这段刨根问底readonlyconst关键字的文章画上了一个比较完整的句号吧。
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½
„hQŸàÕE÷www.netcsharp.cní£ê1½”‡z½