透过IL看C# (外一篇)——警惕常量陷阱
透过IL看C# (外一篇)
警惕常量陷阱
原文地址:http://www.cnblogs.com/AndersLiu/archive/2008/11/23/csharp-via-il-constant-a.html
原创:Anders Liu
摘要:常量的含义本是“永远不会变的量”,但是如果作为类库开发人员,把常量用作“可以由我变,但不能由你变”的量,那就可能铸成大错了。
下面是老刘写的一个类库中的一个类:
代码1 - 老刘的“类库”
其中的常量Version表示类库的当前版本,而方法GetVersion会给出描述当前版本的字符串。用下面的命令行可以将其编译为一个DLL:
csc /t:library Library.cs
接下来,一个倒霉的家伙从老刘这买了这个类库,写了自己的程序:
代码2 - 老刘的“消费者”
这个家伙用下面的命令行编译了自己的程序:
csc /r:Library.dll Program.cs
运行程序,一切正常,屏幕显示出预期的结果:
Library Version: 1
You are currently using version 1.
过了两天,老刘升级代码了。都升级哪些部分了呢?把Version的值改成2了,然后重新编译了Library。所以代码就不贴了。前面这个家伙因为很乖,从老刘这里买了正版,所以老刘承诺免费升级50次,因此他拿到了新版的Library.dll。
当这个家伙再跑自己的程序(注意他没有重新编译自己的代码),问题来了:
Library Version: 1
You are currently using version 2.
我们看到,通过常量访问得到的版本依然是1,而通过类库方法得到的版本字符串是2。
这是怎么回事呢?让我们祭出ILDasm,看一下Version常量的定义:
代码3 - IL中的常量定义
Version定义中的关键字literal表明,这是一个字面常量值。“字面”意味着其值将被直接编译到IL代码中,而不会保留对这个常量的引用。
因此,当我们看到Program.cs中Main方法的IL代码后,就不那么吃惊了:
代码4 - 引用Version常量部分的IL代码
我们可以看到,这里根本没有Version这个常量的影子。只有IL_0006: ldc.i4.1这一行直接加载了数值1——在编译Program的时候,类库中Version常量的值。
有朋友可能想说,那重新编译一下Program不就解决问题了?可问题在于,.NET的一个重要原则就是部署容易和消除DLL陷阱。不能强制要求客户在类库升级后还要重新编译自己的程序。
所以,对于类库设计人员来说,当暴露一个公开的常量时要非常小心,只有确信一个值永远不会发生变化(包括今后的一系列升级)时,才能使用常量。否则请使用只读(只有get访问器)属性或只读(readonly)字段来返回这样的值。
返回目录:透过IL看C#
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!