优质生活
一点一滴
博客园
社区
首页
新随笔
联系
管理
订阅
随笔- 22 文章- 0 评论- 28
条款二 : 运行时常量(readonly)优于编译时常量(const)
C#语言有两种不同的常量机制:一种为编译时(complie-time)常量,一种为运行时(runtime)常量。两种常量有着迥异的行为,使用不正确会导致程序的性能下降或者出现错误。编译时常量比运行时常量稍微快一点,但却缺乏灵活性。只有在性能非常关键,并且其值永远不会变的情况下,我们才应该使用编译时常量。
在C#中,我们使用readonly关键字来声明运行时常量,用const关键字来声明编译时常量。
//
编译时常量:
public
const
int
_Millennium
=
2000
;
//
运行时常量:
public
static
readonly
int
_ThisYear
=
2004
;
编译时常量与运行时常量行为的不同处在于它们的访问方式。编译时常量在编译后的结果代码中会被替换为该常量的值。
if
(myDateTime.Year
==
_Millennium)
其编译后的IL和下面的代码编译后的IL一样:
if
(myDateTime.Year
==
2000
)
运行时常量的值则在运行时被计算。对于使用运行时常量的代码,其编译后的IL将维持对readonly变量(而非它的值)的引用。
这种差别会为我们使用两种常量类型带来一些限制。编译时常量只可以用于基元类型(包括内建的整数类型和浮点类型)、枚举类型或字符串类型。因为只有这些类型才允许我们在初始化器中指定有意义的常量值。(声明的同时初始化)。在使用这些常量的代码编译后得到的IL代码中,常量直接被替换为它们的字面值(literal)。例如,下面的代码就不会通过编译。事实上,C#不允许我们使用new操作符来初始化一个编译时常量,即使被初始化的常量类型是一个值类型。
//
下面的代码不会通过编译,但是换成readonly就可以:
private
const
DateTime _classCreation
=
new
DateTime(
2000
,
1
,
1
,
0
,
0
,
0
);
编译时常量仅限于数值和字符串。只读(readonly)字段之所以也被称作一种常量,是因为它们的构造器一旦被执行,我们将不能对它们的值做任何修改。与编译时常量不同的地方在于,只读字段的赋值操作发生在运行时,因此它们具有更多的灵活性。比如,只读字段的类型就没有任何限制。对于只读字段,我们只能在构造器或者初始化器中为它们赋值。在上面的代码中,我们可以声明readonly的DateTime结构变量,但是不能声明const的DateTime结构变量。
我们可以声明readonly的实例常量,从而为一个类型的每个实例存储不同的值。但是const修饰的编译时常量默认就被定义为静态常量。
我们知道,运行时常量和编译时常量最重要的区别就在于运行时常量值的辨析发生在运行时,而编译时常量值的辨析发生在编译时。换言之,使用运行时常量编译后的IL代码引用的是readonly变量,而非它的值;而使用编译时常量编译后的IL代码将直接引用它的值---就像我们直接在代码中使用常量值一样。即使我们使用的是数值常量并跨程序集引用,情况也是一样:如果在程序集A中引用程序集B中的常量,那么编译后程序集A中出现的那个常量将被它的值所替换。这种差别对于代码的维护性而言有着相当的影响。
编译时常量与运行时常量被解析的方式影响着运行时的兼容性。假设我们在一个名为Infrastructure的程序集中分别定义了一个const字段和一个readonly字段:
public
class
UsefulValues
{
public
static
readonly
int
StartValue
=
5
;
public
const
int
EndValue
=
10
;
}
在另外一个程序集Application中,我们又引用着这些值:
for
(
int
i
=
UsefulValues.StartValue; i
<
UsefulValues.EndValue; i
++
)
{
Console.WriteLine(
"
value is {0}
"
, i);
}
如果我们运行上面的代码,将得到以下输出:
Value is 5
Value is 6
……
Value is 9
假设随着时间的推移,我们又发布了一个新版的Infrastructure程序集:
public
class
UsefulValues
{
public
static
readonly
int
StartValue
=
105
;
public
const
int
EndValue
=
120
;
}
我们将新版的Infrastructure程序集分发出去,但并没有重新编译Application程序集。我们期望得到如下的输出:
Value is 105
Value is 106
……
Value is 109
但实际上,我们却没有得到任何输出。因为现在那个循环语句将使用105作为它的起始值,使用10作为它的结束条件。其根本原因在于C#编译器在第一次编译Application程序集时,将其中的EndValue替换成了它对应的常量值10。而对于StartValue来说,由于它被声明为readonly,所以它的解析发生在运行时。因此,Application程序集在没有被重新编译的情况下,仍然可以使用新的StartVale值。为了改变所有使用readonly常量的客户代码的行为,简单地安装一个新版的Infrastructure程序集就足够了。“更改一个运行时常量的值”应该被视作对类型接口的更改,其后果是我们必须重新编译所有引用该常量的代码。
使用const较之于使用readonly的唯一好处就是性能:使用已知常量值的代码效率要比访问readonly值的代码效率稍好一点。但是这其中的效率提升势非常小的,大家应该和其所失去的灵活性进行一番权衡比较。在打算放弃灵活性之前,一定要对两者的性能差别做一个评测。
综上所述,只有当某些情况要求变量的值必须在编译时可用,才应该考虑使用const,例如:特性(attribute)类的参数,枚举定义,以及某些不随组件版本变化而改变的值。否则,对于其他任何情况,都应该优先选择readonly常量,从而获得其所具有的灵活性。
posted @ 2008-05-07 17:02
kunkun
阅读(41)
评论(0)
编辑
收藏
网摘
所属分类:
Effective C#中文版的读书摘要
新用户注册
刷新评论列表
标题
姓名
主页
Email
(博主才能看到)
验证码
*
看不清,换一张
[
登录
][
注册
]
内容(请不要发表任何与政治相关的内容)
网站首页
新闻频道
社区
小组
博问
网摘
人才
找找看
Remember Me?
登录
使用高级评论
新用户注册
返回页首
恢复上次提交
[使用Ctrl+Enter键可以直接提交]
该文被作者在 2008-05-07 17:26 编辑过
Google站内搜索
相关文章:
相关链接:
所属分类的其他文章:
条款4:使用Conditional特性代替#if条件编译
条款三 : 操作符is或as优于强制转型
条款二 : 运行时常量(readonly)优于编译时常量(const)
条款一 : 使用属性代替可访问的数据成员
最新IT新闻:
李彦宏首次表态竞价排名问题:有错能改善莫大焉
杨致远发表博客解释辞职原因
微软公布免费安全软件计划
《时代》:杨致远被Google玩弄于股掌之间?
Mozilla即将结束对FireFox 2的支持
公告
我的最新闪存
Silverlight
11-6 15:42
<
2008年5月
>
日
一
二
三
四
五
六
27
28
29
30
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
1
2
3
4
5
6
7
与我联系
发短消息
搜索
常用链接
我的随笔
我的空间
我的短信
我的评论
更多链接
我的参与
我的新闻
最新评论
我的标签
留言簿
给我留言
查看留言
我管理的小组
.NET 新手小组
我参加的小组
每日一句英语
蛋蛋日语学堂
ASP.NET
jQuery
NHibernate
Ezsocio
生活杂谈
程序员音乐空间
软件工程师日语
随笔分类
ASP.NET(1)
(rss)
Effective C#中文版的读书摘要(4)
(rss)
JQuery(1)
(rss)
读书笔记 (1)
(rss)
生活&&随想(6)
(rss)
数据结构
(rss)
英语学习
(rss)
自考(计算机软件专业)
(rss)
随笔档案
2008年11月 (1)
2008年10月 (3)
2008年7月 (1)
2008年6月 (1)
2008年5月 (6)
2007年7月 (1)
我的好友
小力
最新评论
1. re: 一段两个人之间的对话
@kayianna
谢谢。^^ (kunkun)
2. re: 一段两个人之间的对话
加油!~!~! (kayianna)
3. re: 上海库瑞信息技术服务有限公司招聘ASP.NET开发工程师
kankan,我能不能去! (VisualStudio)
4. re: 上海库瑞信息技术服务有限公司招聘ASP.NET开发工程师
这个好呀,好像挺熟的名字,
不知道去面试过没 (水木)
5. re: 上海库瑞信息技术服务有限公司招聘ASP.NET开发工程师
@李永京
^^,帮朋友代发一贴。 (kunkun)
阅读排行榜
1. 上海库瑞信息技术服务有限公司招聘ASP.NET开发工程师(989)
2. 如何为Adobe Reader加入自己的书签(84)
3. o(∩_∩)o...,今天去博客园了!(78)
4. 条款4:使用Conditional特性代替#if条件编译(58)
5. 条款二 : 运行时常量(readonly)优于编译时常量(const)(41)
评论排行榜
1. 上海库瑞信息技术服务有限公司招聘ASP.NET开发工程师(11)
2. o(∩_∩)o...,今天去博客园了!(5)
3. 值类型和引用类型的比较(4)
4. 这个周末生病了!(2)
5. 一段两个人之间的对话(2)