透过IL看C# (外一篇)——警惕常量陷阱

警惕常量陷阱
本文通过一个实例揭示了.NET中常量使用不当可能导致的问题。当类库升级改变常量值时,若客户端未同步更新,会导致程序状态不一致。文章建议在无法确保常量永不改变时,采用只读属性或字段代替。

透过IL看C# (外一篇)
警惕常量陷阱

摘要:常量的含义本是“永远不会变的量”,但是如果作为类库开发人员,把常量用作“可以由我变,但不能由你变”的量,那就可能铸成大错了。

下面是老刘写的一个类库中的一个类:

代码1 - 老刘的“类库”

namespace AndersLiu.CSharpViaIL.Constant_Library { public class Library { public const int Version = 1; public string GetVersion() { return string.Format("You are currently using version {0}.", Version); } } }

其中的常量Version表示类库的当前版本,而方法GetVersion会给出描述当前版本的字符串。用下面的命令行可以将其编译为一个DLL:

csc /t:library Library.cs

接下来,一个倒霉的家伙从老刘这买了这个类库,写了自己的程序:

代码2 - 老刘的“消费者”

namespace AndersLiu.CSharpViaIL.Constant_Program { using System; using AndersLiu.CSharpViaIL.Constant_Library; class Program { static void Main() { Console.WriteLine("Library Version: {0}", Library.Version); Library lib = new Library(); string verstr = lib.GetVersion(); Console.WriteLine(verstr); } } }

这个家伙用下面的命令行编译了自己的程序:

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中的常量定义

.field public static literal int32 Version = int32(0x00000002)

Version定义中的关键字literal表明,这是一个字面常量值。“字面”意味着其值将被直接编译到IL代码中,而不会保留对这个常量的引用。

因此,当我们看到Program.cs中Main方法的IL代码后,就不那么吃惊了:

代码4 - 引用Version常量部分的IL代码

IL_0001: ldstr "Library Version: {0}" IL_0006: ldc.i4.1 IL_0007: box [mscorlib]System.Int32 IL_000c: call void [mscorlib]System.Console::WriteLine(string, object)

我们可以看到,这里根本没有Version这个常量的影子。只有IL_0006: ldc.i4.1这一行直接加载了数值1——在编译Program的时候,类库中Version常量的值。

有朋友可能想说,那重新编译一下Program不就解决问题了?可问题在于,.NET的一个重要原则就是部署容易和消除DLL陷阱。不能强制要求客户在类库升级后还要重新编译自己的程序。

所以,对于类库设计人员来说,当暴露一个公开的常量时要非常小心,只有确信一个值永远不会发生变化(包括今后的一系列升级)时,才能使用常量。否则请使用只读(只有get访问器)属性或只读(readonly)字段来返回这样的值。

返回目录:透过IL看C#

转载于:https://www.cnblogs.com/AndersLiu/archive/2008/11/23/csharp-via-il-constant-a.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值