用Visual Studio寫程式的人,不知有沒有注意過AssemblyInfo.cs裡的這個屬性:

[assembly: AssemblyVersion("1.0.*")]

如果你有手動去修改過它,恭喜你! 代表你參與的專案已達一定規模,或是你寫的程式跟元件已經在外開枝散葉,子孫多到要用什麼"字輩"來搞清楚血緣尊卑。XD

不過,或許有些人還不知道微軟版本號碼裡四個數字的用法,可能也不知道Visual Studio專案中版號設成1.0.*時的自動跳號規則。今天剛好有同事問到這件事,我就順手把它整理一下。

微軟慣用的版本編號分為四組數字,例如: 1.0.2553.14653,這四個數字依序是:

  • Major Version: 主版號,大多在大規模的功能、架構變革時才會更動
  • Minor Version: 次版號,用於小規模的功能、架構修正。一般而言,這兩個版號變更意味某些方法參數、型別的變動,有可能導致元件的不相容。
  • Build: 組建,一般用來區別程式是在哪一天組建(Build)的。在軟體工程中,有所謂的Daily Build法,透過每天重新編譯並重新進行測試,確保每天在進行的程式碼修改沒把整個軟體搞爛。而軟體要正式發行時,也會從諸多的Build中挑出一個問題最少,品質最好的先選作Release Candidate。
  • Revision: 修訂,一般保留給為了修復特定錯誤的後續組建,有時也稱作Emergency Bug Fix。(常用於Quick Fix Engineering, QFE, Hotfix的版次標示)

更詳細的資料可以參考MSDN文章: 元件版本控制

想知道.NET程式/元件的版號,我們可以用Windows檔案總管來檢視。EXE、DLL檔案的內容視窗,第二個Tab裡就可以看到版本資訊,還包含發行公司等資訊,且不限.NET編譯的。(這招在調查來路不明檔案時,格外有用。)

了解了版號的意義,另一個有趣的問題是: 當我們設成"1.0.*"時,Visual Studio會如何自動跳號決定Build及Revision?

答案是由Build的日期與時間決定,Build = 以2000/01/01起算的天數,Revision = 以凌晨00:00:00起算的秒數除以2。

用以上的WinForm35.exe來驗算一下,程式的編譯日期時間是2008/07/22 08:08:26,而版號為1.0.3125.14653。所以我們叫出Mini C# Lab,寫個兩行Code:

DateTime d = new DateTime(2000, 1, 1);
Console.WriteLine(d.AddDays(3125).AddSeconds(14653 * 2).ToString("yyyy/MM/dd HH:mm:ss"));
 

薑薑薑薑,計算結果正是: 2008/07/22 08:08:26!

[2008-07-30更新] 感謝Tom補充,AssemblyFileVersion可以避免變更AssemblyVersion衍生的重新編譯需求,在實務上也很常被拿來做成版本識別的依據。引用Tom的說明如下:

"既然提到AssemblyVersion, 我想也可以順便提一下 AssemblyFileVersion.

因為被參考的 DLL 其實會被綁定某個 AssemblyVersion, 所以若因為小修正而改變了 AssemblyVersion, 會造成其他參考他的 DLL 必須跟著重新編譯, 所以我們大都是用 AssemblyFileVersion 來做版本判別.

只有當 interface 改變, 才異動 AssemblyVersion, 否則若只是修正 bug 或是加強內部演算法, interface 不變的狀況下, 都只改變 AssemblyFileVersion."

【2015-11-25補充】還有一種AssemblyInformationVersion!

【瑣事便利貼】
當孝子剝荔枝給兒子吃,吃了兩口,他忽然故做有學問狀,十分認真地"教"我:
吃荔枝的時候要小心哦,裡面的"骨頭"不可以吃...  (哈! 當場全家笑翻)

一般來說,骨頭外面是肉,外面再包覆一層皮。那麼,剥開荔枝"皮",看到荔枝"肉"裡面包的便是荔枝"骨頭"囉? 似乎也有幾份道理。

這孩子果真有邏輯演繹能力,頗有乃父之風,不錯不錯。


Comments

# by Will 保哥

如此「小事」的細節都能夠研究的如此透徹,佩服~佩服~

# by Tom

既然提到AssemblyVersion, 我想也可以順便提一下 AssemblyFileVersion. 因為被參考的 DLL 其實會被綁定某個 AssemblyVersion, 所以若因為小修正而改變了 AssemblyVersion, 會造成其他參考他的 DLL 必須跟著重新編譯, 所以我們大都是用 AssemblyFileVersion 來做版本判別. 只有當 interface 改變, 才異動 AssemblyVersion, 否則若只是修正 bug 或是加強內部演算法, interface 不變的狀況下, 都只改變 AssemblyFileVersion. FYI

# by Tom

既然提到AssemblyVersion, 我想也可以順便提一下 AssemblyFileVersion. 因為被參考的 DLL 其實會被綁定某個 AssemblyVersion, 所以若因為小修正而改變了 AssemblyVersion, 會造成其他參考他的 DLL 必須跟著重新編譯, 所以我們大都是用 AssemblyFileVersion 來做版本判別. 只有當 interface 改變, 才異動 AssemblyVersion, 否則若只是修正 bug 或是加強內部演算法, interface 不變的狀況下, 都只改變 AssemblyFileVersion. FYI

# by Jeffrey

to Tom, 謝謝你的寶貴分享,已將你的補充納入本文。

# by Gravitic

我是對岸來的,寫的很好,加油

# by QOO

不知道為什麼,我的DLL專案AssemblyFileVersion 設成1.0.* 但compile出來都還是1.0.0.0

# by Jeffrey

to QOO, 你是指AssemblyFileVersion設定1.0.*,第一張圖的上方的File Version(非Other version information區)出現1.0.0.0嗎?能否弄個小專案重現問題?

# by QOO

開一個全新專案,還是一樣?... // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 // 指定為預設值: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyFileVersion("1.0.*")] 結果: 檔案版本:1.0.0.0 產品版本:1.0.*

# by Jeffrey

to QOO, 經過查證,這才發現AssemblyFileVersion不支援自動跳號[ http://www.codeproject.com/Questions/685048/Automatic-increase-AssemblyFileVersion 謝謝你的回饋,我又學到新東西。

# by QOO

果然. 只設定[assembly: AssemblyVersion("1.0.*")] 就可以了 感謝大大

# by knock

感謝黑大 測試成功了 但是這樣的時間蠻難辨識的 有辦法變成1.0.yyyyMMdd.HHmmss之類的方式嗎

# by Jeffrey

to knock, 版本數字的範圍為0-65534(參考: https://goo.gl/vBQJ5h Metadata restricts the major, minor, build, and revision components for an assembly to a maximum value of UInt16.MaxValue - 1.),yyyyMMdd與HHmmss不符規格。如果不想用系統提供的自動跳號規格,得自己寫編譯腳本處理。

Post a comment