編譯器錯誤 CS0029
更新:2007 年 11 月
錯誤訊息
無法將型別 'type' 隱含轉換為 'type'
編譯器需要明確轉換。例如,您可能需要將右值 (R-Value) 轉型成與左值 (L-Value) 相同的型別。否則,您必須提供轉換常式以支援特定的運算子多載。
在將某個型別的變數設定給不同型別的變數時一定會發生轉換。在不同型別的變數之間進行設定時,編譯器必須先將指派 (Assignment) 運算子右方的型別轉換成指派運算子左方的型別。以下列程式碼為例:
int i = 50;
long lng = 100;
i = lng;
i = lng; 將會進行設定,但是指派運算子左方和右方的變數資料型別並不相符。在進行設定之前,編譯器會隱含地將型別為 long 的變數 lng 轉換為 int。這是隱含的,因為沒有程式碼明確地指示編譯器執行這項轉換。這個程式碼的問題是它被視為縮小轉換,而編譯器並不允許隱含的縮小轉換,因為這可能會損失資料。
縮小轉換發生於您將佔用較多記憶體儲存空間的資料型別轉換成佔用較少空間的資料型別時;例如,將 long 轉換為 int 變是縮小轉換。long 佔用 8 位元組的記憶體,而 int 只佔用 4 位元組。若要檢視資料損失的狀況,可考慮下列範例:
int i = 50;
long lng = 3147483647;
i = lng;
變數 lng 現在包含一個無法儲存於變數 i 內的數值,因為它太大了。若要將此數值轉換成 int 型別,我們將會損失一些資料,而轉換出來的數值將和轉換前的數值不同。
擴展轉換則和縮小轉換相反。就擴展轉換而言,我們是將佔用較少記憶體儲存空間的資料型別轉換成佔用較多空間的資料型別。以下列出擴展轉換的範例:
int i = 50;
long lng = 100;
lng = i;
請注意這個程式碼範例和第一個的差別。這一次變數 lng 是在指派運算子左方,因此它是這次設定的目標 (Target)。在進行設定之前,編譯器必須先隱含地將型別為 int 的 i 變數轉換為型別 long。這是擴展轉換,因為我們是將佔用 4 位元組記憶體的型別 (int) 轉換成佔用 8 位元組記憶體的型別 (long)。隱含擴展轉換是允許的,因為這並不會損失資料。任何可儲存於 int 內的數值也可以儲存於 long 內。
我們知道隱含縮小轉換並不被允許,因此若要編譯這種程式碼,我們需要明確地轉換資料型別。明確轉換是透過轉型 (Casting) 來進行的。轉型為 C# 用來描述將一種資料型別轉換為另一種的用語。若要讓程式碼進行編譯,我們需要使用下列語法:
int i = 50;
long lng = 100;
i = (int) lng; // cast to int
程式碼的第三行告訴編譯器在進行設定前,先明確地將型別為 long 的 lng 變數轉換為 int。請記住縮小轉換可能會損失資料。在使用縮小轉換時需特別小心,因為雖然程式碼可編譯,執行階段時仍可能得到非預期的結果。
這項討論僅適用於實值型別 (Value Type)。在使用實值型別時,您將直接使用變數內所儲存的資料;不過,.NET Framework 還包含了參考型別 (Reference Type)。在處理參考型別時,您處理的是變數的參考,而非實質資料。參考型別的範例包括了類別、介面和陣列。您不能明確或隱含的將參考型別轉換至其他型別,除非編譯器允許特定轉換,或者已實作適當的轉換運算子。
下列範例會產生 CS0029:
// CS0029.cs
public class MyInt
{
private int x = 0;
// Uncomment this conversion routine to resolve CS0029
/*
public static implicit operator int(MyInt i)
{
return i.x;
}
*/
public static void Main()
{
MyInt myInt = new MyInt();
int i = myInt; // CS0029
}
}