C#中经常用const或者readonly来定义不可改变常量,那么如何使用它们呢?
主要内容:
- const和readonly的区别
- readonly的补充说明
1. const和readonly的区别
主要的区别在于 const是在编译时确定值的,readonly是在运行时确定值的。
因此,用const修饰的字段,必须在定义的时候就赋值,否则编译器报错。
而readonly修饰的字段除了可以在定义时赋值以外,还可以在构造函数中赋值。
验证的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
using
System;
namespace
Test7
{
public
class
CLRviaCSharp_7
{
const
string
cValue =
"const"
;
readonly
string
rValue;
public
CLRviaCSharp_7()
{
rValue =
"readonly"
;
}
static
void
Main(
string
[] args)
{
CLRviaCSharp_7 test7 =
new
CLRviaCSharp_7();
Console.WriteLine(
"cValue="
+ CLRviaCSharp_7.cValue);
Console.WriteLine(
"rValue="
+ test7.rValue);
Console.ReadKey(
true
);
}
}
}
|
编译后用ILSpy查看IL代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
.class public auto ansi beforefieldinit CLRviaCSharp_7
extends object
{
// Fields
.field private static literal string cValue = "const"
.field private initonly string rValue
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20c7
// Code size 21 (0x15)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldstr "readonly"
IL_000e: stfld string class Test7.CLRviaCSharp_7::rValue
IL_0013: nop
IL_0014: ret
} // End of method CLRviaCSharp_7..ctor
.method private static hidebysig
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x20e0
// Code size 48 (0x30)
.maxstack 2
.entrypoint
.locals init (
[0] class Test7.CLRviaCSharp_7 test7
)
IL_0000: nop
IL_0001: newobj instance void Test7.CLRviaCSharp_7::.ctor()
IL_0006: stloc.0
IL_0007: ldstr "cValue=const"
IL_000c: call void [mscorlib]System.Console::WriteLine(string)
IL_0011: nop
IL_0012: ldstr "rValue="
IL_0017: ldloc.0
IL_0018: ldfld string class Test7.CLRviaCSharp_7::rValue
IL_001d: call string string::Concat(string, string)
IL_0022: call void [mscorlib]System.Console::WriteLine(string)
IL_0027: nop
IL_0028: ldc.i4.1
IL_0029: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
IL_002e: pop
IL_002f: ret
} // End of method CLRviaCSharp_7.Main
} // End of class Test7.CLRviaCSharp_7
|
从Main函数中的IL_0007,我们可以看出,编译时就已经将 cValue替换为字符串"const"了,所以在Main函数中看不出使用了字段cValue
从Main函数中的IL_0018,我们可以看出,运行时才读取 rValue的值,将其拼接到输出的字符串中。
2. readonly的补充说明
const和readonly虽然都可以定义常量,但是由于readonly是在运行时才确定值的,所以比const更加灵活。
当然,readonly的性能肯定比const稍逊。(具体相差多少还没有试验过)
readonly与const相比,使用时需要注意2点。
2.1. readonly的字段可以通过反射来修改
具体参见以下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
using
System;
using
System.Reflection;
namespace
Test7
{
public
class
CLRviaCSharp_7
{
static
void
Main(
string
[] args)
{
ChangeReadonlyClass cr =
new
ChangeReadonlyClass();
Console.WriteLine(
"before change, rValue="
+ cr.rValue);
// 利用反射来改变ChangeReadonlyClass中readonly字段的值
FieldInfo fi =
typeof
(ChangeReadonlyClass).GetField(
"rValue"
);
fi.SetValue(cr,
"rValue has changed"
);
Console.WriteLine(
"after change, rValue="
+ cr.rValue);
Console.ReadKey(
true
);
}
}
public
class
ChangeReadonlyClass
{
public
readonly
string
rValue;
public
ChangeReadonlyClass()
{
rValue =
"ChangeReadonlyClass's readonly field"
;
}
}
}
|
运行结果如下:
2.2. readonly的字段为引用类型时,不可改变的是引用,而不是引用的对象。
验证代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
using
System;
namespace
Test7
{
public
class
CLRviaCSharp_7
{
public
static
readonly
Char[] rValues =
new
Char[] {
'X'
,
'Y'
,
'Z'
};
static
void
Main(
string
[] args)
{
// 修改引用的对象,可以成功修改并运行
rValues[0] =
'A'
;
rValues[1] =
'B'
;
rValues[2] =
'C'
;
// 修改引用本身,无法编译
rValues =
new
Char[] {
'A'
,
'B'
,
'C'
};
Console.ReadKey(
true
);
}
}
}
|
readonly并不像const那样是绝对的常量。我们在利用其灵活性的同时,也应注意它可能带来的副作用。
本文转自wang_yb博客园博客,原文链接:http://www.cnblogs.com/wang_yb/archive/2011/06/29/2092886.html,如需转载请自行联系原作者