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

來源:互聯網
上載者:User
透過IL看C# (外一篇)
警惕常量陷阱

原文地址:http://www.cnblogs.com/AndersLiu/archive/2008/11/23/csharp-via-il-constant-a.html

原創:Anders Liu

摘要:常量的含義本是“永遠不會變的量”,但是如果作為類庫開發人員,把常量用作“可以由我變,但不能由你變”的量,那就可能鑄成大錯了。

下面是老劉寫的一個類庫中的一個類:

代碼1 - 老劉的“類庫”

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

其中的常量Version表示類庫的目前的版本,而方法GetVersion會給出描述目前的版本的字串。用下面的命令列可以將其編譯為一個DLL:

csc /t:library Library.cs

接下來,一個倒黴的傢伙從老劉這買了這個類庫,寫了自己的程式:

代碼2 - 老劉的“消費者”

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

這個傢伙用下面的命令列編譯了自己的程式:

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}"<br />IL_0006: ldc.i4.1<br />IL_0007: box [mscorlib]System.Int32<br />IL_000c: call void [mscorlib]System.Console::WriteLine(string,<br /> object)<br />

我們可以看到,這雷根本沒有Version這個常量的影子。只有IL_0006: ldc.i4.1這一行直接載入了數值1——在編譯Program的時候,類庫中Version常量的值。

有朋友可能想說,那重新編譯一下Program不就解決問題了?可問題在於,.NET的一個重要原則就是部署容易和消除DLL陷阱。不能強制要求客戶在類庫升級後還要重新編譯自己的程式。

所以,對於類庫設計人員來說,當暴露一個公開的常量時要非常小心,只有確信一個值永遠不會發生變化(包括今後的一系列升級)時,才能使用常量。否則請使用唯讀(只有get訪問器)屬性或唯讀(readonly)欄位來返回這樣的值。

返回目錄:透過IL看C#

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.