無法將類型 'type' 隱含轉換成 'type'
編譯器需要明確轉換。 例如,您可能需要將右值轉換成與左值相同的類型。 否則,您必須提供轉換常式,以支援特定運算子多載。
將某種類型的變數指派給不同類型的變數時,一定會發生轉換。 在不同類型的變數之間進行指派時,編譯器必須將指派運算子右邊的類型,轉換成指派運算子左邊的類型。 以下面這段程式碼來說:
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 是在指派運算子的左邊,因此是我們的指派目標。 編譯器必須將 int 類型的變數 i 隱含轉換成 long 類型,才能進行指派。 這是擴展轉換,因為我們是將佔用 4 個位元組記憶體的類型 (int),轉換成佔用 8 個位元組記憶體的類型 (long)。 因為不可能遺失資料,所以允許隱含的擴展轉換。 任何可以儲存在 int 中的值,也可以儲存在 long 中。
我們知道不允許隱含的縮小轉換,因此若要編譯此程式碼,我們需要明確轉換資料類型。 明確轉換是透過轉型來進行。 「轉型」是 C# 中用來描述將某種資料類型轉換成另一種的字詞。 若要讓程式碼進行編譯,我們需要使用下列語法:
int i = 50;
long lng = 100;
i = (int) lng; // Cast to int.
程式碼的第三行會指示編譯器將 long 類型的變數 lng 隱含轉換成 int,再進行指派。 請記住,若使用縮小轉換,則有可能會遺失資料。 請謹慎使用縮小轉換,即使程式碼會編譯,您還是可能會在執行階段收到非預期的結果。
此討論僅適用於實值型別。 使用實值型別時,您是直接處理儲存在變數中的資料。 不過,.NET 也有參考型別。 使用參考型別時,您是處理變數的參考,而不是實際資料。 類別、介面和陣列都是參考型別的例子。 除非編譯器允許特定轉換,或實作適當的轉換運算子,否則您無法將某種參考型別隱含或明確轉換成另一種。
下列範例會產生 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()
{
var myInt = new MyInt();
int i = myInt; // CS0029
}
}