c#中的readonly,const与enum枚举大家都不会陌生
偶有空就来试试此三种类型的使用问题,其实CLR via中都有啦,高手可以略过
写一个测试类,如下。编译成一个单独的DLL
namespace lib
{
public class jm
{
public const string TSString = "a const string";
public readonly static string TSReadonly = "a readonly string";
public enum TSEnum
{
t1 = 0
}
}
}
再搞一个控制台程 序,很简就是为了调用上面的变量:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("const:" lib.jm.TSString);
Console.WriteLine("readonly:" lib.jm.TSReadonly);
Console.WriteLine("Enum:" lib.jm.TSEnum.t1.GetHashCode().ToString());
Console.ReadLine();
}
}
引用上面的lib,如此的结果大家当然都知道.
好了。现在我们改变上面的lib中变量的值如下:
namespace lib
{
public class jm
{
public const string TSString = "a const string 2";
public readonly static string TSReadonly = "a readonly string 2";
public enum TSEnum
{
t1 = 2
}
}
}
我们在字符串后都加上2,枚兴的值也改为2
编译些DLL,但我们不重新编译调用的控制台程序,直接把DLL拷到控制台的debug下,替换原DLL,运行exe结果如下
除了readonly变化了以外。其余二个都没变。
为什么呢,我们可以用.net relector查看下il代码
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init ( [0] int32 CS$0$0000)
L_0000: nop
L_0001: ldstr "const:a const string"
L_0006: call void [mscorlib]System.Console::WriteLine(string)
L_000b: nop
L_000c: ldstr "readonly:"
L_0011: ldsfld string [lib]lib.jm::TSReadonly
L_0016: call string [mscorlib]System.String::Concat(string, string)
L_001b: call void [mscorlib]System.Console::WriteLine(string)
L_0020: nop
L_0021: ldstr "Enum:"
L_0026: ldc.i4.1
L_0027: box [lib]lib.jm/TSEnum
L_002c: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
L_0031: stloc.0
L_0032: ldloca.s CS$0$0000
L_0034: call instance string [mscorlib]System.Int32::ToString()
L_0039: call string [mscorlib]System.String::Concat(string, string)
L_003e: call void [mscorlib]System.Console::WriteLine(string)
L_0043: nop
L_0044: call string [mscorlib]System.Console::ReadLine()
L_0049: pop
L_004a: ret
}
我用红色标注的地方就可以看出原因了
const变量被编译后,调用的地方会直接内联值过去,枚举也类似,但readonly却不成,
所以这就是const的高效的地方了。
但当一个dll中的const 或enum改变把,其它使用它的程 序集也得重新编译。
其实const与readonly变量大家应该早就知道吧。我只是没想到eunm也是如此。学艺不精啊
补充:
当我把显示枚举的地方改为:Console.WriteLine("Enum:" lib.jm.TSEnum.t1.ToString());
输出为Enum:t1
这没有问题
然后我把枚举改为:
public enum TSEnum
{
t2 = 1
}
也就是改变了枚举的t1为t2
然后拷贝DLL过来运行,得到的结果是Enum:t2.
所以它还是通过内联了值1再反过去找到值为1的t2。所以显示也是正确的
但当我把枚举改为:
public enum TSEnum
{
t2 = 2
}
也就是t1变为了t2,t1=1变为了t2=2
这时它就傻了。运行结果变成:Enum:1
只是把内联的值打印了出来。因为它找不到对应的枚举值了。
反编译可以看出“
L_0021: ldstr "Enum:"
L_0026: ldc.i4.1
L_0027: box [lib]lib.jm/TSEnum
把枚举的值装箱打印出来。所以是1