你可能自己從來 不會寫這樣的代碼,但是,卻讓編譯器自動從一個指定的類型轉化為 System.Object,這確實是你做的。編譯器只是想試著幫助你,它想讓你成功(調 用函數),它也很樂意在必要時候為你生成裝箱和拆箱語句,從而把一個值類型 數據轉化成System.Object的實例。為了避免這麼挑剔的懲罰,在使用它們來調 用WriteLine之前,你自己應該把你的類型轉化成字符串的實例。
Console.WriteLine("A few numbers:{0}, {1}, {2} ",
25.ToString(), 32.ToString(), 50.ToString ());
(譯注:注意,在自己調用ToString方法時,還是會在堆上 創建一個引用實例,但它的好處是不用拆箱,因為對象已經是一個引用類型了。 )
這段代碼使用已知的整數類型,而且值類型再也不會隱式的轉化為 System.Object類型。這個常見的例子展示了避免裝箱的第一個規則:注意隱式 的轉化為System.Object,如果可以避免,值類型不應該被System.Object代替。
另一個常見情況就是,在使用.Net 1.x的集合時,你可能無意的把一個 值類型轉化成System.Object類型。任何時候,當你添加一個值類型數據到集合 時中,你就創建了一個箱子。任何時候從集合中移出一個對象時,你得到的是箱 子裡的一個拷貝。從箱子裡取一個對象時,你總是要創建一個拷貝。這會在應用 程序中產生一些隱藏的BUG。編譯器是不會幫你查找這些BUG的。這都是裝箱惹的 禍。讓我們開始創建一個簡單的結構,可以修改其中一個字段,並且把它的一些 實例對象放到一個集合中:
public struct Person
{
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
public override string ToString( )
{
Return _Name;
}
}
// Using the Person in a collection:
ArrayList attendees = new ArrayList( );
Person p = new Person( "Old Name" );
attendees.Add( p );
// Try to change the name:
// Would work if Person was a reference type.
Person p2 = (( Person )attendees[ 0 ] );
p2.Name = "New Name";
// Writes "Old Name":
Console.WriteLine(
attendees[ 0 ].ToString( ));