黄宣龙
asker_pachelbel@hotmail.com
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