【轉】由string與String談起

黃宣龍

[email protected]

string or String?

如果你是個C#初學者,也許你曾經懷疑過這個問題:「書上不是說C#是個大小寫有別的語言嗎?那爲什麼這兩個程序都可以跑?」

using System;

 

class Class1

{

    static void Main(string[]args)

    {

       string s = "I lovenetmag.";

       //這個string是小寫開頭

       Console.WriteLine(s);

    }

}

 

using System;

 

class Class1

{

    static void Main(string[]args)

    {

       String s = "I lovenetmag.";

       //這個String是大寫開頭

       Console.WriteLine(s);

    }

}

事實上,這兩個程序不但都能跑,如果你使用ildasm來看這兩段程序代碼編譯出來的IL碼的話,你還會發現這兩個程序根本就產生了一模一樣的IL碼。這到底是怎麼一回事呢,這兩段程序代碼究竟有沒有差別呢?

內建型別(PredefinedType)

按照坊間升研究所補習班教的答題技巧指導來看,若這一題只有10分,答案應該是「String指的是System.String類別,而string則是C#內建的關鍵詞。事實上,string正是對應到System.String類別,也可說string是System.String類別在C#中的化名(alias),因此兩段C#程序代碼都會編譯出相同的IL碼,對於CLR而言這兩者是沒什麼差別的。」

若是這題被配了有40分呢?那也許我們得由什麼叫做內建型別(PredefinedType)談起。

內建型別,又稱做原生型別(PrimitiveType),顧名思義就是一個語言內建的型別。也就是說,一個符合該語言標準的編譯器,應該要能直接支持這種型別。一般來講,這意味着該語言應該會爲該型別規範出一個語言關鍵詞,而編譯器要能認得這個關鍵詞並在編譯時產生適當的碼。以C#來說,像是整數(int),浮點數(float),字符串(string)等都是內建型別,你可以直接使用這些關鍵詞撰寫你的程序,而C#編譯器將能看懂這些關鍵詞併爲你編譯出適當的IL碼供執行之用。這邊還有個比較不嚴謹的簡陋講法,「程序語言有提供化名(alias)的型別就是該語言的內建型別了」。

爲什麼需要內建型別呢?

爲什麼要讓編譯器支持這些關鍵詞來對應這些型別呢?有一個原因是因爲這些型別實在太常用了,透過這樣的方式會方便許多。當你想要用一個變量來儲存年齡時,你想要怎麼寫呢?是

int age = 20;

還是

System.Int32 age = new System.Int32();

age = 20;

畢竟整數,浮點數,字符,字符串等型別在程序中實在太常用了。如果每次都得來一行

System.Int32 age = new System.Int32();

實在吃不消不是嗎?

此外,內建型別也意味着編譯器在設計時就已經瞭解這些型別的實作細節,所以編譯器對於內建型別可以有更多的處理知識,因而能更有彈性且有力的處理這些型別。舉例來說,在使用內建型別時我們可以不用new來new去,一行

int i = 10;

就通通搞定。而在將精度較低的內建型別轉型至精度較高的內建型別時我們可以不需多做指示地讓它隱式轉型(Implicitcast):

int i = 20;

double j = i;

請注意,這和衍生類別能自動向上轉型(upcast)爲基底類別的情況並不一樣,因爲int並不是繼承double而來,他們都是繼承自System.ValueType,換言之,在繼承體系之中,他們倆是平行的。此例之中int之所以能自動地轉型成double乃是因爲編譯器知道int和double這兩個內建型別是做什麼用的,並判斷出可以無害的將int轉型爲double,因此能順利編譯過關且正常運作。

那麼,到底要String還是string呢?

現在,你應該已經知道什麼叫內建型別,也瞭解到String和string到最後都是一樣的,因爲這兩種程序代碼都會產生相同的IL碼。那麼,我們到底應該使用哪種風格來撰寫程序呢?在C#語言規格書1.2.1中是這樣說的:「As a matter ofstyle, use of the keyword is favored over use of the complete system type name.」很明顯地它的建議是使用關鍵詞。不過相反的主張也有人支持,基本精神是認爲使用FCL名稱會使程序較爲清楚,因爲同一個FCL型別在不同語言也許會使用不同的別名(alias),或是相同的別名在不同的程序語言中可能會對應到不同的FCL型別,使用FCL名稱可以避免必須使用多種語言工作或不熟悉此語言的程序設計師產生混淆。舉例來說,如果程序中是清清楚楚的宣告成Int32,那無庸置疑地這個變量就是Int32。但若是宣告爲long,那在某些語言可能是對應到Int32,有些則是對應到Int64。基本上,我個人是覺得兩種風格間沒有明顯優劣差異,所以依你自己的喜好擇一即可,唯一的建議是「最好不要混用」。混用會導致程序風格混亂,在閱讀和維護上都有可能造成困擾。

結語

本文有點小題大作地討論了內建型別相關的議題,看完本文後您應該瞭解了何謂內建型別,以及它存在的理由,也瞭解到在C#中使用語言關鍵詞或是FCL類別名稱宣告變量對底層而言都是一樣的。當然,也知道了爲什麼寫String或string都可以。


參考資料

·        Applied Microsoft .NET Framework Programming

·        C# Language Specification.doc

附註

本文已刊載於 .NET 電子雜誌 http://www.netmag.com.tw

發佈了4 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章