《CLR Via C# 第3版》笔记之(七) - const和readonly

简介:

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" ;
         }
         
     }
}

运行结果如下:

image

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,如需转载请自行联系原作者

目录
相关文章
|
3月前
|
C# Python
C# 笔记1 - 操作目录
C# 笔记1 - 操作目录
29 0
|
3月前
|
C# Python
C# 笔记3 - 重载一系列像python那样的print()方法
C# 笔记3 - 重载一系列像python那样的print()方法
27 1
|
3月前
|
存储 C# C++
C# 笔记2 - 数组、集合与与文本文件处理
C# 笔记2 - 数组、集合与与文本文件处理
46 0
|
10月前
|
存储 网络协议 Java
C# 快速入门笔记
C# 快速入门笔记
C# 快速入门笔记
|
C# 开发工具
C#滑动拼图验证码实现笔记
C# 是一个现代的、通用的、面向对象的编程语言,它是由微软(Microsoft)开发的,由 Ecma 和 ISO 核准认可的。突发奇想,动手开发一个C#滑动拼图验证码,下面是我开发过程的记录。
C#滑动拼图验证码实现笔记
|
SQL 开发框架 算法
【读书笔记】《Effective C#》50条建议笔记整理
对《Effective C#:改善C#代码的50个有效方法》一书整理的读书笔记。
28073 5
【读书笔记】《Effective C#》50条建议笔记整理
|
C# 数据库
C#编程-65:读取数据库DataReader对象复习笔记
C#编程-65:读取数据库DataReader对象复习笔记
C#编程-65:读取数据库DataReader对象复习笔记
|
C# 数据库
C#编程-65:数据库Command对象复习笔记
C#编程-65:数据库Command对象复习笔记
C#编程-65:数据库Command对象复习笔记
|
C# 数据库
C#编程-65:连接数据库复习笔记
C#编程-65:连接数据库复习笔记
C#编程-65:连接数据库复习笔记
C#编程-64:ADO.NET对象模型复习笔记
C#编程-64:ADO.NET对象模型复习笔记
C#编程-64:ADO.NET对象模型复习笔记