.NET Framework 中的類型轉換Type Conversion in the .NET Framework

每個值都有相關聯的類型,該類型定義屬性,例如配置給值的空間量、能夠擁有的可能值範圍,以及提供的成員。Every value has an associated type, which defines attributes such as the amount of space allocated to the value, the range of possible values it can have, and the members that it makes available. 許多值都可以表示成多種類型。Many values can be expressed as more than one type. 例如,數值 4 就可以表示成整數值或浮點 (Floating-Point) 值。For example, the value 4 can be expressed as an integer or a floating-point value. 類型轉換會建立新類型的值,與舊類型的值相等,但是不一定會保留原始物件的識別 (或實際的值)。Type conversion creates a value in a new type that is equivalent to the value of an old type, but does not necessarily preserve the identity (or exact value) of the original object.

.NET Framework 自動支援下列轉換︰The .NET Framework automatically supports the following conversions:

  • 從衍生類別轉換成基底類別。Conversion from a derived class to a base class. 舉例來說,這表示任何類別或結構的執行個體都可以轉換成 Object 執行個體。This means, for example, that an instance of any class or structure can be converted to an Object instance. 這種轉換不需要轉型或轉換運算子。This conversion does not require a casting or conversion operator.

  • 從基底類別轉換回原始的衍生類別。Conversion from a base class back to the original derived class. 在 C# 中,這種轉換需要轉型運算子。In C#, this conversion requires a casting operator. 在 Visual Basic 中,如果已 Option Strict 開啟則需要 CType 運算子。In Visual Basic, it requires the CType operator if Option Strict is on.

  • 從實作介面的類型轉換成代表該介面的介面物件。Conversion from a type that implements an interface to an interface object that represents that interface. 這種轉換不需要轉型或轉換運算子。This conversion does not require a casting or conversion operator.

  • 從介面物件轉換回實作該介面的原始類型。Conversion from an interface object back to the original type that implements that interface. 在 C# 中,這種轉換需要轉型運算子。In C#, this conversion requires a casting operator. 在 Visual Basic 中,如果已 Option Strict 開啟則需要 CType 運算子。In Visual Basic, it requires the CType operator if Option Strict is on.

除了這些自動轉換以外,.NET Framework 還提供多個支援自訂類型轉換的功能。In addition to these automatic conversions, the .NET Framework provides several features that support custom type conversion. 這些需求包括下列各項:These include the following:

使用隱含運算子的隱含轉換Implicit Conversion with the Implicit Operator

擴展轉換包含從現有類型的值來建立新的值,這個類型具有比目標類型更嚴格的範圍或更受限制的成員清單。Widening conversions involve the creation of a new value from the value of an existing type that has either a more restrictive range or a more restricted member list than the target type. 擴展轉換不可能導致資料遺失 (雖然可能導致精確度降低)。Widening conversions cannot result in data loss (although they may result in a loss of precision). 因為不可能遺失資料,編譯器可以隱含地 (或直接地) 處理轉換,而不需要使用明確的轉換方法或轉型運算子。Because data cannot be lost, compilers can handle the conversion implicitly or transparently, without requiring the use of an explicit conversion method or a casting operator.

注意

雖然執行隱含轉換的程式碼可以呼叫轉換方法或使用轉型運算子,但支援隱含轉換的編譯器並不需要這些動作。Although code that performs an implicit conversion can call a conversion method or use a casting operator, their use is not required by compilers that support implicit conversions.

例如,Decimal 類型支援從 ByteCharInt16Int32Int64SByteUInt16UInt32UInt64 值的隱含轉換。For example, the Decimal type supports implicit conversions from Byte, Char, Int16, Int32, Int64, SByte, UInt16, UInt32, and UInt64 values. 下列範例說明其中一部分隱含轉換在指派值給 Decimal 變數時的情形。The following example illustrates some of these implicit conversions in assigning values to a Decimal variable.

byte byteValue = 16;
short shortValue = -1024;
int intValue = -1034000;
long longValue = 1152921504606846976;
ulong ulongValue = UInt64.MaxValue;

decimal decimalValue;

decimalValue = byteValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.", 
                  byteValue.GetType().Name, decimalValue); 
                         
decimalValue = shortValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.", 
                  shortValue.GetType().Name, decimalValue); 

decimalValue = intValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.", 
                  intValue.GetType().Name, decimalValue); 

decimalValue = longValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.", 
                  longValue.GetType().Name, decimalValue); 
                    
decimalValue = ulongValue;
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.", 
                  longValue.GetType().Name, decimalValue); 
// The example displays the following output:
//    After assigning a Byte value, the Decimal value is 16.
//    After assigning a Int16 value, the Decimal value is -1024.
//    After assigning a Int32 value, the Decimal value is -1034000.
//    After assigning a Int64 value, the Decimal value is 1152921504606846976.
//    After assigning a Int64 value, the Decimal value is 18446744073709551615.
Dim byteValue As Byte = 16
Dim shortValue As Short = -1024
Dim intValue As Integer = -1034000
Dim longValue As Long = CLng(1024^6)
Dim ulongValue As ULong = ULong.MaxValue

Dim decimalValue As Decimal

decimalValue = byteValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
                  byteValue.GetType().Name, decimalValue) 
                         
decimalValue = shortValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
                  shortValue.GetType().Name, decimalValue) 

decimalValue = intValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
                  intValue.GetType().Name, decimalValue) 

decimalValue = longValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
                  longValue.GetType().Name, decimalValue) 
                  
decimalValue = ulongValue
Console.WriteLine("After assigning a {0} value, the Decimal value is {1}.",
                  longValue.GetType().Name, decimalValue) 
' The example displays the following output:
'    After assigning a Byte value, the Decimal value is 16.
'    After assigning a Int16 value, the Decimal value is -1024.
'    After assigning a Int32 value, the Decimal value is -1034000.
'    After assigning a Int64 value, the Decimal value is 1152921504606846976.
'    After assigning a Int64 value, the Decimal value is 18446744073709551615.

如果特定的語言編譯器支援自訂運算子,您也可以在自己的自訂類型中定義隱含轉換。If a particular language compiler supports custom operators, you can also define implicit conversions in your own custom types. 下列範例針對使用正負號和大小表示之名為 ByteWithSign 的帶正負號位元組資料類型,提供部分實作。The following example provides a partial implementation of a signed byte data type named ByteWithSign that uses sign-and-magnitude representation. 它支援將 ByteSByte 值隱含轉換為 ByteWithSign 值。It supports implicit conversion of Byte and SByte values to ByteWithSign values.

public struct ByteWithSign
{
   private SByte signValue; 
   private Byte value;
   
   public static implicit operator ByteWithSign(SByte value) 
   {
      ByteWithSign newValue;
      newValue.signValue = (SByte) Math.Sign(value);
      newValue.value = (byte) Math.Abs(value);
      return newValue;
   }  
   
   public static implicit operator ByteWithSign(Byte value)
   {
      ByteWithSign  newValue;
      newValue.signValue = 1;
      newValue.value = value;
      return newValue;
   }
   
   public override string ToString()
   { 
      return (signValue * value).ToString();
   }
}
Public Structure ByteWithSign
   Private signValue As SByte 
   Private value As Byte
   
   Public Overloads Shared Widening Operator CType(value As SByte) As ByteWithSign
      Dim newValue As ByteWithSign
      newValue.signValue = CSByte(Math.Sign(value))
      newValue.value = CByte(Math.Abs(value))
      Return newValue
   End Operator  
   
   Public Overloads Shared Widening Operator CType(value As Byte) As ByteWithSign
      Dim NewValue As ByteWithSign
      newValue.signValue = 1
      newValue.value = value
      Return newValue
   End Operator
   
   Public Overrides Function ToString() As String 
      Return (signValue * value).ToString()
   End Function
End Structure

然後,用戶端程式碼可以宣告 ByteWithSign 變數並指派 ByteSByte 值給它,而不需要執行任何明確的轉換,也不需要使用任何轉型運算子,如下列範例所示。Client code can then declare a ByteWithSign variable and assign it Byte and SByte values without performing any explicit conversions or using any casting operators, as the following example shows.

SByte sbyteValue = -120;
ByteWithSign value = sbyteValue;
Console.WriteLine(value);
value = Byte.MaxValue;
Console.WriteLine(value);
// The example displays the following output:
//       -120
//       255
Dim sbyteValue As SByte = -120
Dim value As ByteWithSign = sbyteValue
Console.WriteLine(value.ToString()) 
value = Byte.MaxValue
Console.WriteLine(value.ToString()) 
' The example displays the following output:
'       -120
'       255

使用明確運算子的明確轉換Explicit Conversion with the Explicit Operator

縮小轉換包含從現有類型的值來建立新的值,這個類型具有比目標類型更廣的範圍或更大的成員清單。Narrowing conversions involve the creation of a new value from the value of an existing type that has either a greater range or a larger member list than the target type. 因為縮小轉換可能導致資料遺失,編譯器通常會要求必須透過呼叫轉換方法或轉型運算子來明確執行轉換。Because a narrowing conversion can result in a loss of data, compilers often require that the conversion be made explicit through a call to a conversion method or a casting operator. 也就是說,開發人員程式碼中必須明確處理轉換。That is, the conversion must be handled explicitly in developer code.

注意

縮小轉換需要轉換方法或轉型運算子的主要目的是讓開發人員知道可能遺失資料,或可能發生 OverflowException,以便在程式碼中處理。The major purpose of requiring a conversion method or casting operator for narrowing conversions is to make the developer aware of the possibility of data loss or an OverflowException so that it can be handled in code. 不過,某些編譯器可能會放寬這項需求。However, some compilers can relax this requirement. 例如,在 Visual Basic 中,如果 Option Strict 已關閉 (此為預設),則 Visual Basic 編譯器會嘗試隱含地執行縮小轉換。For example, in Visual Basic, if Option Strict is off (its default setting), the Visual Basic compiler tries to perform narrowing conversions implicitly.

例如,UInt32Int64UInt64 資料類型的範圍超過 Int32 資料類型的範圍,如下表所示。For example, the UInt32, Int64, and UInt64 data types have ranges that exceed that the Int32 data type, as the following table shows.

輸入Type 與 Int32 的範圍比較Comparison with range of Int32
Int64 Int64.MaxValue 大於 Int32.MaxValue,而 Int64.MinValue 小於 (負值範圍大於) Int32.MinValueInt64.MaxValue is greater than Int32.MaxValue, and Int64.MinValue is less than (has a greater negative range than) Int32.MinValue.
UInt32 UInt32.MaxValue 大於 Int32.MaxValueUInt32.MaxValue is greater than Int32.MaxValue.
UInt64 UInt64.MaxValue 大於 Int32.MaxValueUInt64.MaxValue is greater than Int32.MaxValue.

為了處理縮小轉換,.NET Framework 允許類型定義 Explicit 運算子。To handle such narrowing conversions, the .NET Framework allows types to define an Explicit operator. 然後,個別語言編譯器就可以使用自己的語法來實作這個運算子,也可以呼叫 Convert 類別的成員來執行轉換。Individual language compilers can then implement this operator using their own syntax, or a member of the Convert class can be called to perform the conversion. (如需有關 Convert 類別的詳細資訊,請參閱本主題稍後的 Convert 類別)。下列範例說明如何使用語言功能來處理將這些可能超出範圍的整數值明確轉換成 Int32 值。(For more information about the Convert class, see The Convert Class later in this topic.) The following example illustrates the use of language features to handle the explicit conversion of these potentially out-of-range integer values to Int32 values.

long number1 = int.MaxValue + 20L;
uint number2 = int.MaxValue - 1000;
ulong number3 = int.MaxValue;

int intNumber;

try {
   intNumber = checked((int) number1);
   Console.WriteLine("After assigning a {0} value, the Integer value is {1}.", 
                     number1.GetType().Name, intNumber); 
}
catch (OverflowException) {
   if (number1 > int.MaxValue)
      Console.WriteLine("Conversion failed: {0} exceeds {1}.", 
                        number1, int.MaxValue);
   else
      Console.WriteLine("Conversion failed: {0} is less than {1}.", 
                        number1, int.MinValue);
}

try {
   intNumber = checked((int) number2);
   Console.WriteLine("After assigning a {0} value, the Integer value is {1}.", 
                     number2.GetType().Name, intNumber); 
}
catch (OverflowException) {
   Console.WriteLine("Conversion failed: {0} exceeds {1}.", 
                     number2, int.MaxValue);
}

try {
   intNumber = checked((int) number3);
   Console.WriteLine("After assigning a {0} value, the Integer value is {1}.", 
                     number3.GetType().Name, intNumber); 
}
catch (OverflowException) {
   Console.WriteLine("Conversion failed: {0} exceeds {1}.", 
                     number1, int.MaxValue);
}

// The example displays the following output:
//    Conversion failed: 2147483667 exceeds 2147483647.
//    After assigning a UInt32 value, the Integer value is 2147482647.
//    After assigning a UInt64 value, the Integer value is 2147483647.
Dim number1 As Long = Integer.MaxValue + 20L
Dim number2 As UInteger = Integer.MaxValue - 1000
Dim number3 As ULong = Integer.MaxValue

Dim intNumber As Integer

Try
   intNumber = CInt(number1)
   Console.WriteLine("After assigning a {0} value, the Integer value is {1}.", 
                       number1.GetType().Name, intNumber)
Catch e As OverflowException
   If number1 > Integer.MaxValue Then
      Console.WriteLine("Conversion failed: {0} exceeds {1}.", 
                                        number1, Integer.MaxValue)
   Else
      Console.WriteLine("Conversion failed: {0} is less than {1}.\n", 
                                        number1, Integer.MinValue)
   End If
End Try

Try
   intNumber = CInt(number2)
   Console.WriteLine("After assigning a {0} value, the Integer value is {1}.", 
                       number2.GetType().Name, intNumber)
Catch e As OverflowException
   Console.WriteLine("Conversion failed: {0} exceeds {1}.", 
                                     number2, Integer.MaxValue)
End Try

Try
   intNumber = CInt(number3)
   Console.WriteLine("After assigning a {0} value, the Integer value is {1}.", 
                       number3.GetType().Name, intNumber)
Catch e As OverflowException
   Console.WriteLine("Conversion failed: {0} exceeds {1}.",
                                     number1, Integer.MaxValue)
End Try
' The example displays the following output:
'    Conversion failed: 2147483667 exceeds 2147483647.
'    After assigning a UInt32 value, the Integer value is 2147482647.
'    After assigning a UInt64 value, the Integer value is 2147483647.

明確轉換在不同的語言中可能會產生不同的結果,這些結果可能與對應的 Convert 方法所傳回的值不同。Explicit conversions can produce different results in different languages, and these results can differ from the value returned by the corresponding Convert method. 例如,如果 Double 值 12.63251 轉換為 Int32,則 Visual Basic CInt 方法與 .NET Framework Convert.ToInt32(Double) 方法都會四捨五入 Double 而傳回 13,但 C# (int) 運算子會截斷 Double 而傳回 12。For example, if the Double value 12.63251 is converted to an Int32, both the Visual Basic CInt method and the .NET Framework Convert.ToInt32(Double) method round the Double to return a value of 13, but the C# (int) operator truncates the Double to return a value of 12. 同樣地,C# (int) 運算子不支援布林值對整數的轉換,但 Visual Basic CInt 方法會將 true 的值轉換為 -1。Similarly, the C# (int) operator does not support Boolean-to-integer conversion, but the Visual Basic CInt method converts a value of true to -1. 另一方面,Convert.ToInt32(Boolean) 方法會將 true 的值轉換為 1。On the other hand, the Convert.ToInt32(Boolean) method converts a value of true to 1.

大多數的編譯器都允許明確轉換以已檢查或未檢查的方式執行。Most compilers allow explicit conversions to be performed in a checked or unchecked manner. 如果執行已檢查的轉換,當要轉換之類型的值不在目標類型的範圍內時,則會擲回 OverflowExceptionWhen a checked conversion is performed, an OverflowException is thrown when the value of the type to be converted is outside the range of the target type. 在同樣的狀況下執行未檢查的轉換時,轉換可能不會擲回例外狀況,但實際行為會變得不明確,且可能產生不正確的值。When an unchecked conversion is performed under the same conditions, the conversion might not throw an exception, but the exact behavior becomes undefined and an incorrect value might result.

注意

在 C# 中,已檢查的轉換可以透過使用 checked 關鍵字搭配轉型運算子來執行,也可以指定 /checked+ 編譯器選項來執行。In C#, checked conversions can be performed by using the checked keyword together with a casting operator, or by specifying the /checked+ compiler option. 相反地,未檢查的轉換可使用 unchecked 關鍵字搭配轉型運算子來執行,或可以指定 /checked- 編譯器選項來執行。Conversely, unchecked conversions can be performed by using the unchecked keyword together with the casting operator, or by specifying the /checked- compiler option. 根據預設,明確轉換是未檢查的。By default, explicit conversions are unchecked. 在 Visual Basic 中,已檢查的轉換可藉由清除專案的 [進階編譯器設定] 對話方塊中的 [移除整數的溢位檢查] 核取方塊來執行,或可以指定 /removeintchecks- 編譯器選項來執行。In Visual Basic, checked conversions can be performed by clearing the Remove integer overflow checks check box in the project's Advanced Compiler Settings dialog box, or by specifying the /removeintchecks- compiler option. 相反地,未檢查的轉換可以藉由選取專案的 [進階編譯器設定] 對話方塊中的 [移除整數的溢位檢查] 核取方塊來執行,也可以指定 /removeintchecks+ 編譯器選項來執行。Conversely, unchecked conversions can be performed by selecting the Remove integer overflow checks check box in the project's Advanced Compiler Settings dialog box or by specifying the /removeintchecks+ compiler option. 根據預設,明確轉換是檢查的。By default, explicit conversions are checked.

下列 C# 範例使用 checkedunchecked 關鍵字,說明將超出 Byte 範圍的值轉換為 Byte 時的行為差異。The following C# example uses the checked and unchecked keywords to illustrate the difference in behavior when a value outside the range of a Byte is converted to a Byte. 已檢查的轉換會擲回例外狀況,但未檢查的轉換會指派 Byte.MaxValueByte 變數。The checked conversion throws an exception, but the unchecked conversion assigns Byte.MaxValue to the Byte variable.

   int largeValue = Int32.MaxValue;
   byte newValue;
   
   try {
      newValue = unchecked((byte) largeValue);
      Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.", 
                        largeValue.GetType().Name, largeValue,
                        newValue.GetType().Name, newValue);
   }
   catch (OverflowException) {
      Console.WriteLine("{0} is outside the range of the Byte data type.", 
                        largeValue);
   }

   try {
      newValue = checked((byte) largeValue);
      Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.", 
                        largeValue.GetType().Name, largeValue,
                        newValue.GetType().Name, newValue);
   }
   catch (OverflowException) {
      Console.WriteLine("{0} is outside the range of the Byte data type.", 
                        largeValue);
   }
   // The example displays the following output:
   //    Converted the Int32 value 2147483647 to the Byte value 255.
   //    2147483647 is outside the range of the Byte data type.

如果特定的語言編譯器支援自訂多載運算子,您也可以在自己的自訂類型中定義明確轉換。If a particular language compiler supports custom overloaded operators, you can also define explicit conversions in your own custom types. 下列範例針對使用正負號和大小表示之名為 ByteWithSign 的帶正負號位元組資料類型,提供部分實作。The following example provides a partial implementation of a signed byte data type named ByteWithSign that uses sign-and-magnitude representation. 它支援將 Int32UInt32 值明確轉換為 ByteWithSign 值。It supports explicit conversion of Int32 and UInt32 values to ByteWithSign values.

public struct ByteWithSign
{
   private SByte signValue; 
   private Byte value;

   private const byte MaxValue = byte.MaxValue;
   private const int MinValue = -1 * byte.MaxValue;
   
   public static explicit operator ByteWithSign(int value) 
   {
      // Check for overflow.
      if (value > ByteWithSign.MaxValue || value < ByteWithSign.MinValue)
         throw new OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.", 
                                                   value));
      
      ByteWithSign newValue;
      newValue.signValue = (SByte) Math.Sign(value);
      newValue.value = (byte) Math.Abs(value);
      return newValue;
   }  
   
   public static explicit operator ByteWithSign(uint value)
   {
      if (value > ByteWithSign.MaxValue) 
         throw new OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.", 
                                                   value));

      ByteWithSign newValue;
      newValue.signValue = 1;
      newValue.value = (byte) value;
      return newValue;
   }
   
   public override string ToString()
   { 
      return (signValue * value).ToString();
   }
}
Public Structure ByteWithSign
   Private signValue As SByte 
   Private value As Byte
   
   Private Const MaxValue As Byte = Byte.MaxValue
   Private Const MinValue As Integer = -1 * Byte.MaxValue

   Public Overloads Shared Narrowing Operator CType(value As Integer) As ByteWithSign
      ' Check for overflow.
      If value > ByteWithSign.MaxValue Or value < ByteWithSign.MinValue Then
         Throw New OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.", value))
      End If
      
      Dim newValue As ByteWithSign
      
      newValue.signValue = CSByte(Math.Sign(value))
      newValue.value = CByte(Math.Abs(value))
      Return newValue
   End Operator
   
   Public Overloads Shared Narrowing Operator CType(value As UInteger) As ByteWithSign
      If value > ByteWithSign.MaxValue Then 
         Throw New OverflowException(String.Format("'{0}' is out of range of the ByteWithSign data type.", value))
      End If
       
      Dim NewValue As ByteWithSign

      newValue.signValue = 1
      newValue.value = CByte(value)
      Return newValue
   End Operator
   
   Public Overrides Function ToString() As String 
      Return (signValue * value).ToString()
   End Function
End Structure

然後,用戶端程式碼可以宣告 ByteWithSign 變數並指派 Int32UInt32 值給它 (如果指派包含轉型運算子或轉換方法的話),如下列範例所示。Client code can then declare a ByteWithSign variable and assign it Int32 and UInt32 values if the assignments include a casting operator or a conversion method, as the following example shows.

ByteWithSign value;

try {
   int intValue = -120;
   value = (ByteWithSign) intValue;
   Console.WriteLine(value);
}
catch (OverflowException e) {
   Console.WriteLine(e.Message);
}

try {
   uint uintValue = 1024;
   value = (ByteWithSign) uintValue;
   Console.WriteLine(value);
}
catch (OverflowException e) {
    Console.WriteLine(e.Message);
}
// The example displays the following output:
//       -120
//       '1024' is out of range of the ByteWithSign data type.
Dim value As ByteWithSign
 
Try  
   Dim intValue As Integer = -120
   value = CType(intValue, ByteWithSign)
   Console.WriteLine(value) 
Catch e As OverflowException
   Console.WriteLine(e.Message)
End Try

Try
   Dim uintValue As UInteger = 1024
   value = CType(uintValue, ByteWithSign)
   Console.WriteLine(value) 
Catch e As OverflowException
   Console.WriteLine(e.Message)
End Try
' The example displays the following output:
'       -120
'       '1024' is out of range of the ByteWithSign data type.

IConvertible 介面The IConvertible Interface

為了支援從任何類型轉換至通用語言執行平台基底類型,.NET Framework 提供 IConvertible 介面。To support the conversion of any type to a common language runtime base type, the .NET Framework provides the IConvertible interface. 實作類型需要提供下列項目:The implementing type is required to provide the following:

  • 傳回實作類型之 TypeCode 的方法。A method that returns the TypeCode of the implementing type.

  • 將實作類型轉換為每一個通用語言執行平台基底類型 (BooleanByteDateTimeDecimalDouble 等) 的方法。Methods to convert the implementing type to each common language runtime base type (Boolean, Byte, DateTime, Decimal, Double, and so on).

  • 將實作類型的執行個體轉換為另一個指定之類型的通用轉換方法。A generalized conversion method to convert an instance of the implementing type to another specified type. 不支援的轉換應該擲回 InvalidCastExceptionConversions that are not supported should throw an InvalidCastException.

每一個通用語言執行平台基底類型 (也就是 BooleanByteCharDateTimeDecimalDoubleInt16Int32Int64SByteSingleStringUInt16UInt32UInt64),以及 DBNullEnum 類型,都實作 IConvertible 介面。Each common language runtime base type (that is, the Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte, Single, String, UInt16, UInt32, and UInt64), as well as the DBNull and Enum types, implement the IConvertible interface. 不過,這些都是明確的介面實作,且只能透過 IConvertible 介面變數來呼叫轉換方法,如下列範例所示。However, these are explicit interface implementations; the conversion method can be called only through an IConvertible interface variable, as the following example shows. 這個範例將 Int32 值轉換為其對等的 Char 值。This example converts an Int32 value to its equivalent Char value.

int codePoint = 1067;
IConvertible iConv = codePoint;
char ch = iConv.ToChar(null);
Console.WriteLine("Converted {0} to {1}.", codePoint, ch);
Dim codePoint As Integer = 1067
Dim iConv As IConvertible = codePoint
Dim ch As Char = iConv.ToChar(Nothing)
Console.WriteLine("Converted {0} to {1}.", codePoint, ch)

由於必須呼叫其介面上的轉換方法,而不是呼叫實作類型上的轉換方法,這種需求使得明確介面實作相當耗費資源。The requirement to call the conversion method on its interface rather than on the implementing type makes explicit interface implementations relatively expensive. 相反地,在通用語言執行平台基底類型之間轉換時,我們建議您呼叫 Convert 類別的適當成員。Instead, we recommend that you call the appropriate member of the Convert class to convert between common language runtime base types. 如需詳細資訊,請參閱下一節 Convert 類別For more information, see the next section, The Convert Class.

注意

除了 .NET Framework 提供的 IConvertible 介面和 Convert 類別之外,個別語言可能還會提供執行轉換的方式。In addition to the IConvertible interface and the Convert class provided by the .NET Framework, individual languages may also provide ways to perform conversions. 例如,C# 使用轉型 (Casting) 運算子、Visual Basic 使用編譯器實作的轉換函式,例如 CTypeCIntDirectCastFor example, C# uses casting operators; Visual Basic uses compiler-implemented conversion functions such as CType, CInt, and DirectCast.

在大多數情況下,IConvertible 介面的設計主要是支援在 .NET Framework 中的各基底類型之間轉換。For the most part, the IConvertible interface is designed to support conversion between the base types in the .NET Framework. 不過,也可以使用自訂類型來實作介面,以支援從該類型轉換至其他自訂類型。However, the interface can also be implemented by a custom type to support conversion of that type to other custom types. 如需詳細資訊,請參閱本主題稍後的使用 ChangeType 方法的自訂轉換一節。For more information, see the section Custom Conversions with the ChangeType Method later in this topic.

Convert 類別The Convert Class

雖然可以呼叫每一個基底類別的 IConvertible 介面實作來執行類型轉換,但建議的語言中立方式是呼叫 System.Convert 類別的方法,在不同的基底類型之間轉換。Although each base type's IConvertible interface implementation can be called to perform a type conversion, calling the methods of the System.Convert class is the recommended language-neutral way to convert from one base type to another. 此外,也可以使用 Convert.ChangeType(Object, Type, IFormatProvider) 方法將指定的自訂類型轉換為另一種類型。In addition, the Convert.ChangeType(Object, Type, IFormatProvider) method can be used to convert from a specified custom type to another type.

在基底類型之間轉換Conversions Between Base Types

Convert 類別提供在基底類型之間轉換的語言中立方式,且所有以通用語言執行平台為目標的語言都可以使用。The Convert class provides a language-neutral way to perform conversions between base types and is available to all languages that target the common language runtime. 它對於擴展和縮小轉換提供一組完整的方法,且對於不支援的轉換會擲回 InvalidCastException (例如,將 DateTime 值轉換為整數值)。It provides a complete set of methods for both widening and narrowing conversions, and throws an InvalidCastException for conversions that are not supported (such as the conversion of a DateTime value to an integer value). 縮小轉換是在已檢查的情況下執行,如果轉換失敗,則會擲回 OverflowExceptionNarrowing conversions are performed in a checked context, and an OverflowException is thrown if the conversion fails.

重要

因為 Convert 類別包含在每一個基底類型之間來回轉換的方法,所以不需要呼叫每一個基底類型的 IConvertible 明確介面實作。Because the Convert class includes methods to convert to and from each base type, it eliminates the need to call each base type's IConvertible explicit interface implementation.

下列範例說明如何使用 System.Convert 類別,在 .NET Framework 基底類型之間執行數個擴展和縮小轉換。The following example illustrates the use of the System.Convert class to perform several widening and narrowing conversions between .NET Framework base types.

// Convert an Int32 value to a Decimal (a widening conversion).
int integralValue = 12534;
decimal decimalValue = Convert.ToDecimal(integralValue);
Console.WriteLine("Converted the {0} value {1} to " +  
                                  "the {2} value {3:N2}.", 
                                  integralValue.GetType().Name, 
                                  integralValue, 
                                  decimalValue.GetType().Name, 
                                  decimalValue);
// Convert a Byte value to an Int32 value (a widening conversion).
byte byteValue = Byte.MaxValue;
int integralValue2 = Convert.ToInt32(byteValue);                                  
Console.WriteLine("Converted the {0} value {1} to " +  
                                  "the {2} value {3:G}.", 
                                  byteValue.GetType().Name, 
                                  byteValue, 
                                  integralValue2.GetType().Name, 
                                  integralValue2);

// Convert a Double value to an Int32 value (a narrowing conversion).
double doubleValue = 16.32513e12;
try {
   long longValue = Convert.ToInt64(doubleValue);
   Console.WriteLine("Converted the {0} value {1:E} to " +  
                                     "the {2} value {3:N0}.", 
                                     doubleValue.GetType().Name, 
                                     doubleValue, 
                                     longValue.GetType().Name, 
                                     longValue);
}
catch (OverflowException) {
   Console.WriteLine("Unable to convert the {0:E} value {1}.", 
                                     doubleValue.GetType().Name, doubleValue);
}
      
// Convert a signed byte to a byte (a narrowing conversion).     
sbyte sbyteValue = -16;
try {
   byte byteValue2 = Convert.ToByte(sbyteValue);
   Console.WriteLine("Converted the {0} value {1} to " +  
                                     "the {2} value {3:G}.", 
                                     sbyteValue.GetType().Name, 
                                     sbyteValue, 
                                     byteValue2.GetType().Name, 
                                     byteValue2);
}
catch (OverflowException) {
   Console.WriteLine("Unable to convert the {0} value {1}.", 
                                     sbyteValue.GetType().Name, sbyteValue);
}                                         
// The example displays the following output:
//       Converted the Int32 value 12534 to the Decimal value 12,534.00.
//       Converted the Byte value 255 to the Int32 value 255.
//       Converted the Double value 1.632513E+013 to the Int64 value 16,325,130,000,000.
//       Unable to convert the SByte value -16.                                                                  
' Convert an Int32 value to a Decimal (a widening conversion).
Dim integralValue As Integer = 12534
Dim decimalValue As Decimal = Convert.ToDecimal(integralValue)
Console.WriteLine("Converted the {0} value {1} to the {2} value {3:N2}.", 
                  integralValue.GetType().Name,
                  integralValue,
                  decimalValue.GetType().Name,
                  decimalValue)

' Convert a Byte value to an Int32 value (a widening conversion).
Dim byteValue As Byte = Byte.MaxValue
Dim integralValue2 As Integer = Convert.ToInt32(byteValue)                                  
Console.WriteLine("Converted the {0} value {1} to " + 
                                  "the {2} value {3:G}.",
                                  byteValue.GetType().Name,
                                  byteValue,
                                  integralValue2.GetType().Name,
                                  integralValue2)

' Convert a Double value to an Int32 value (a narrowing conversion).
Dim doubleValue As Double = 16.32513e12
Try
   Dim longValue As Long = Convert.ToInt64(doubleValue)
   Console.WriteLine("Converted the {0} value {1:E} to " + 
                                     "the {2} value {3:N0}.",
                                     doubleValue.GetType().Name,
                                     doubleValue,
                                     longValue.GetType().Name,
                                     longValue)
Catch e As OverflowException
   Console.WriteLine("Unable to convert the {0:E} value {1}.",
                                     doubleValue.GetType().Name, doubleValue)
End Try                                                             
      
' Convert a signed byte to a byte (a narrowing conversion).     
Dim sbyteValue As SByte = -16
Try
   Dim byteValue2 As Byte = Convert.ToByte(sbyteValue)
   Console.WriteLine("Converted the {0} value {1} to " + 
                                     "the {2} value {3:G}.",
                                     sbyteValue.GetType().Name,
                                     sbyteValue,
                                     byteValue2.GetType().Name,
                                     byteValue2)
Catch e As OverflowException
   Console.WriteLine("Unable to convert the {0} value {1}.",
                                     sbyteValue.GetType().Name, sbyteValue)
End Try 
' The example displays the following output:
'       Converted the Int32 value 12534 to the Decimal value 12,534.00.
'       Converted the Byte value 255 to the Int32 value 255.
'       Converted the Double value 1.632513E+013 to the Int64 value 16,325,130,000,000.
'       Unable to convert the SByte value -16.                                                                  

在某些情況下,尤其是在浮點值之間來回轉換時,即使沒有擲回 OverflowException,轉換也可能會降低精確度。In some cases, particularly when converting to and from floating-point values, a conversion may involve a loss of precision, even though it does not throw an OverflowException. 下列範例說明這種精確度降低情況。The following example illustrates this loss of precision. 在第一種情況下,Decimal 值在轉換為 Double 時會降低精確度 (有效位數較少)。In the first case, a Decimal value has less precision (fewer significant digits) when it is converted to a Double. 在第二種情況下,Double 值會從 42.72 四捨五入為 43,以完成轉換。In the second case, a Double value is rounded from 42.72 to 43 in order to complete the conversion.

double doubleValue; 

// Convert a Double to a Decimal.
decimal decimalValue = 13956810.96702888123451471211m;
doubleValue = Convert.ToDouble(decimalValue);
Console.WriteLine("{0} converted to {1}.", decimalValue, doubleValue);

doubleValue = 42.72;
try {
   int integerValue = Convert.ToInt32(doubleValue);
   Console.WriteLine("{0} converted to {1}.", 
                                     doubleValue, integerValue);
}
catch (OverflowException) {      
   Console.WriteLine("Unable to convert {0} to an integer.", 
                                     doubleValue);
}   
// The example displays the following output:
//       13956810.96702888123451471211 converted to 13956810.9670289.
//       42.72 converted to 43.
Dim doubleValue As Double 

' Convert a Double to a Decimal.
Dim decimalValue As Decimal = 13956810.96702888123451471211d
doubleValue = Convert.ToDouble(decimalValue)
Console.WriteLine("{0} converted to {1}.", decimalValue, doubleValue)

doubleValue = 42.72
Try
   Dim integerValue As Integer = Convert.ToInt32(doubleValue)
   Console.WriteLine("{0} converted to {1}.",
                                     doubleValue, integerValue)
Catch e As OverflowException
   Console.WriteLine("Unable to convert {0} to an integer.",
                                     doubleValue)
End Try   
' The example displays the following output:
'       13956810.96702888123451471211 converted to 13956810.9670289.
'       42.72 converted to 43.

如需同時列出 Convert 類別所支援之擴展和縮小轉換的表格,請參閱類型轉換表For a table that lists both the widening and narrowing conversions supported by the Convert class, see Type Conversion Tables.

使用 ChangeType 方法的自訂轉換Custom Conversions with the ChangeType Method

Convert 類別除了支援轉換為每一個基底類型,也可以用於將自訂類型轉換為一個或多個預先定義的類型。In addition to supporting conversions to each of the base types, the Convert class can be used to convert a custom type to one or more predefined types. 這種轉換由 Convert.ChangeType(Object, Type, IFormatProvider) 方法執行,而這個方法會進一步包裝對於 IConvertible.ToType 參數之 value 方法的呼叫。This conversion is performed by the Convert.ChangeType(Object, Type, IFormatProvider) method, which in turn wraps a call to the IConvertible.ToType method of the value parameter. 這表示由 value 參數所表示的物件必須提供 IConvertible 介面的實作。This means that the object represented by the value parameter must provide an implementation of the IConvertible interface.

注意

由於 Convert.ChangeType(Object, Type)Convert.ChangeType(Object, Type, IFormatProvider) 方法會使用 Type 物件指定轉換 value 的目標類型,因此這兩種方法可以在編譯時期用來動態轉換不明類型的物件。Because the Convert.ChangeType(Object, Type) and Convert.ChangeType(Object, Type, IFormatProvider) methods use a Type object to specify the target type to which value is converted, they can be used to perform a dynamic conversion to an object whose type is not known at compile time. 但請注意,IConvertiblevalue 實作仍然必須支援這項轉換。However, note that the IConvertible implementation of value must still support this conversion.

下列範例說明 IConvertible 介面可能的實作,這種實作允許 TemperatureCelsius 物件轉換為 TemperatureFahrenheit 物件,反之亦然。The following example illustrates a possible implementation of the IConvertible interface that allows a TemperatureCelsius object to be converted to a TemperatureFahrenheit object and vice versa. 範例中定義一個基底類別 Temperature,這個類別實作 IConvertible 介面並覆寫 Object.ToString 方法。The example defines a base class, Temperature, that implements the IConvertible interface and overrides the Object.ToString method. 衍生的 TemperatureCelsiusTemperatureFahrenheit 類別分別覆寫基底類別的 ToTypeToString 方法。The derived TemperatureCelsius and TemperatureFahrenheit classes each override the ToType and the ToString methods of the base class.

using System;

public abstract class Temperature : IConvertible
{
   protected decimal temp;
   
   public Temperature(decimal temperature)
   {
      this.temp = temperature;
   }

   public decimal Value
   { 
      get { return this.temp; } 
      set { this.temp = value; }        
   }

   public override string ToString()
   {
      return temp.ToString(null as IFormatProvider) + "º";
   }

   // IConvertible implementations.
   public TypeCode GetTypeCode() { 
      return TypeCode.Object;
   }   

   public bool ToBoolean(IFormatProvider provider) {
      throw new InvalidCastException(String.Format("Temperature-to-Boolean conversion is not supported."));
   }
   
   public byte ToByte(IFormatProvider provider) {
      if (temp < Byte.MinValue || temp > Byte.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the Byte data type.", temp));
      else
         return (byte) temp;
   }

   public char ToChar(IFormatProvider provider) {
      throw new InvalidCastException("Temperature-to-Char conversion is not supported.");
   }
   
   public DateTime ToDateTime(IFormatProvider provider) {
      throw new InvalidCastException("Temperature-to-DateTime conversion is not supported.");
   }
   
   public decimal ToDecimal(IFormatProvider provider) {
      return temp;
   }
   
   public double ToDouble(IFormatProvider provider) {
      return (double) temp;
   }
   
   public short ToInt16(IFormatProvider provider) {
      if (temp < Int16.MinValue || temp > Int16.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the Int16 data type.", temp));
      else
         return (short) Math.Round(temp);
   }

   public int ToInt32(IFormatProvider provider) {
      if (temp < Int32.MinValue || temp > Int32.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the Int32 data type.", temp));
      else
         return (int) Math.Round(temp);
   }
   
   public long ToInt64(IFormatProvider provider) {
      if (temp < Int64.MinValue || temp > Int64.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the Int64 data type.", temp));
      else
         return (long) Math.Round(temp);
   }
   
   public sbyte ToSByte(IFormatProvider provider) {
      if (temp < SByte.MinValue || temp > SByte.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the SByte data type.", temp));
      else
         return (sbyte) temp;
   }

   public float ToSingle(IFormatProvider provider) {
      return (float) temp;
   }
   
   public virtual string ToString(IFormatProvider provider) {
      return temp.ToString(provider) + "°";
   }
   
   // If conversionType is implemented by another IConvertible method, call it.
   public virtual object ToType(Type conversionType, IFormatProvider provider) {
      switch (Type.GetTypeCode(conversionType))
      {
         case TypeCode.Boolean:
            return this.ToBoolean(provider);
         case TypeCode.Byte:
            return this.ToByte(provider);
         case TypeCode.Char:
            return this.ToChar(provider);
         case TypeCode.DateTime:
            return this.ToDateTime(provider);
         case TypeCode.Decimal:
            return this.ToDecimal(provider);
         case TypeCode.Double:
            return this.ToDouble(provider);
         case TypeCode.Empty:
            throw new NullReferenceException("The target type is null.");
         case TypeCode.Int16:
            return this.ToInt16(provider);
         case TypeCode.Int32:
            return this.ToInt32(provider);
         case TypeCode.Int64:
            return this.ToInt64(provider);
         case TypeCode.Object:
            // Leave conversion of non-base types to derived classes.
            throw new InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", 
                                           conversionType.Name));
         case TypeCode.SByte:
            return this.ToSByte(provider);
         case TypeCode.Single:
            return this.ToSingle(provider);
         case TypeCode.String:
            IConvertible iconv = this;
            return iconv.ToString(provider);
         case TypeCode.UInt16:
            return this.ToUInt16(provider);
         case TypeCode.UInt32:
            return this.ToUInt32(provider);
         case TypeCode.UInt64:
            return this.ToUInt64(provider);
         default:
            throw new InvalidCastException("Conversion not supported.");
      }
   }
   
   public ushort ToUInt16(IFormatProvider provider) {
      if (temp < UInt16.MinValue || temp > UInt16.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the UInt16 data type.", temp));
      else
         return (ushort) Math.Round(temp);
   }
   
   public uint ToUInt32(IFormatProvider provider) {
      if (temp < UInt32.MinValue || temp > UInt32.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the UInt32 data type.", temp));
      else
         return (uint) Math.Round(temp);
   }
   
   public ulong ToUInt64(IFormatProvider provider) {
      if (temp < UInt64.MinValue || temp > UInt64.MaxValue)
         throw new OverflowException(String.Format("{0} is out of range of the UInt64 data type.", temp));
      else
         return (ulong) Math.Round(temp);
   }
}

public class TemperatureCelsius : Temperature, IConvertible
{
   public TemperatureCelsius(decimal value) : base(value)
   {
   }
   
   // Override ToString methods.
   public override string ToString()
   {
      return this.ToString(null);
   }

   public override string ToString(IFormatProvider provider)
   {
      return temp.ToString(provider) + "°C"; 
   }
   
   // If conversionType is a implemented by another IConvertible method, call it.
   public override object ToType(Type conversionType, IFormatProvider provider) {
      // For non-objects, call base method.
      if (Type.GetTypeCode(conversionType) != TypeCode.Object) {
         return base.ToType(conversionType, provider);
      }   
      else
      {   
         if (conversionType.Equals(typeof(TemperatureCelsius)))
            return this;
         else if (conversionType.Equals(typeof(TemperatureFahrenheit)))
            return new TemperatureFahrenheit((decimal) this.temp * 9 / 5 + 32);
         else
            throw new InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", 
                                           conversionType.Name));
      }
   }
}

public class TemperatureFahrenheit : Temperature, IConvertible 
{
   public TemperatureFahrenheit(decimal value) : base(value)
   {
   }
   
   // Override ToString methods.
   public override string ToString()
   {
      return this.ToString(null);
   }

   public override string ToString(IFormatProvider provider)
   {
      return temp.ToString(provider) + "°F"; 
   }

   public override object ToType(Type conversionType, IFormatProvider provider)
   { 
      // For non-objects, call base methood.
      if (Type.GetTypeCode(conversionType) != TypeCode.Object) {
         return base.ToType(conversionType, provider);
      }   
      else
      {   
         // Handle conversion between derived classes.
         if (conversionType.Equals(typeof(TemperatureFahrenheit))) 
            return this;
         else if (conversionType.Equals(typeof(TemperatureCelsius)))
            return new TemperatureCelsius((decimal) (this.temp - 32) * 5 / 9);
         // Unspecified object type: throw an InvalidCastException.
         else
            throw new InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", 
                                           conversionType.Name));
      }                                 
   }
}   
Public MustInherit Class Temperature
   Implements IConvertible
   
   Protected temp As Decimal
   
   Public Sub New(temperature As Decimal)
      Me.temp = temperature
   End Sub

   Public Property Value As Decimal
      Get 
         Return Me.temp
      End Get
      Set
         Me.temp = Value
      End Set   
   End Property

   Public Overrides Function ToString() As String
      Return temp.ToString() & "º"
   End Function

   ' IConvertible implementations.
   Public Function GetTypeCode() As TypeCode Implements IConvertible.GetTypeCode
      Return TypeCode.Object
   End Function   

   Public Function ToBoolean(provider As IFormatProvider) As Boolean Implements IConvertible.ToBoolean
      Throw New InvalidCastException(String.Format("Temperature-to-Boolean conversion is not supported."))
   End Function
   
   Public Function ToByte(provider As IFormatProvider) As Byte Implements IConvertible.ToByte
      If temp < Byte.MinValue Or temp > Byte.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the Byte data type.", temp))
      Else
         Return CByte(temp)
      End If    
   End Function

   Public Function ToChar(provider As IFormatProvider) As Char Implements IConvertible.ToChar
      Throw New InvalidCastException("Temperature-to-Char conversion is not supported.")
   End Function
   
   Public Function ToDateTime(provider As IFormatProvider) As DateTime Implements IConvertible.ToDateTime
      Throw New InvalidCastException("Temperature-to-DateTime conversion is not supported.")
   End Function
   
   Public Function ToDecimal(provider As IFormatProvider) As Decimal Implements IConvertible.ToDecimal
      Return temp
   End Function
   
   Public Function ToDouble(provider As IFormatProvider) As Double Implements IConvertible.ToDouble
      Return CDbl(temp)
   End Function
   
   Public Function ToInt16(provider As IFormatProvider) As Int16 Implements IConvertible.ToInt16
      If temp < Int16.MinValue Or temp > Int16.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the Int16 data type.", temp))
      End If
      Return CShort(Math.Round(temp))
   End Function

   Public Function ToInt32(provider As IFormatProvider) As Int32 Implements IConvertible.ToInt32
      If temp < Int32.MinValue Or temp > Int32.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the Int32 data type.", temp))
      End If
      Return CInt(Math.Round(temp))
   End Function
   
   Public Function ToInt64(provider As IFormatProvider) As Int64 Implements IConvertible.ToInt64
      If temp < Int64.MinValue Or temp > Int64.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the Int64 data type.", temp))
      End If
      Return CLng(Math.Round(temp))
   End Function
   
   Public Function ToSByte(provider As IFormatProvider) As SByte Implements IConvertible.ToSByte
      If temp < SByte.MinValue Or temp > SByte.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the SByte data type.", temp))
      Else
         Return CSByte(temp)
      End If    
   End Function

   Public Function ToSingle(provider As IFormatProvider) As Single Implements IConvertible.ToSingle
      Return CSng(temp)
   End Function
   
   Public Overridable Overloads Function ToString(provider As IFormatProvider) As String Implements IConvertible.ToString
      Return temp.ToString(provider) & " °C"
   End Function
   
   ' If conversionType is a implemented by another IConvertible method, call it.
   Public Overridable Function ToType(conversionType As Type, provider As IFormatProvider) As Object Implements IConvertible.ToType
      Select Case Type.GetTypeCode(conversionType)
         Case TypeCode.Boolean
            Return Me.ToBoolean(provider)
         Case TypeCode.Byte
            Return Me.ToByte(provider)
         Case TypeCode.Char
            Return Me.ToChar(provider)   
         Case TypeCode.DateTime
            Return Me.ToDateTime(provider)
         Case TypeCode.Decimal
            Return Me.ToDecimal(provider)
         Case TypeCode.Double
            Return Me.ToDouble(provider)
         Case TypeCode.Empty
            Throw New NullReferenceException("The target type is null.")
         Case TypeCode.Int16
            Return Me.ToInt16(provider)
         Case TypeCode.Int32
            Return Me.ToInt32(provider)
         Case TypeCode.Int64
            Return Me.ToInt64(provider)
         Case TypeCode.Object
            ' Leave conversion of non-base types to derived classes.
            Throw New InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", _
                                           conversionType.Name))
         Case TypeCode.SByte
            Return Me.ToSByte(provider)
         Case TypeCode.Single
            Return Me.ToSingle(provider)
         Case TypeCode.String
            Return Me.ToString(provider)
         Case TypeCode.UInt16
            Return Me.ToUInt16(provider)
         Case TypeCode.UInt32
            Return Me.ToUInt32(provider)
         Case TypeCode.UInt64
            Return Me.ToUInt64(provider)
         Case Else
            Throw New InvalidCastException("Conversion not supported.")   
      End Select
   End Function
   
   Public Function ToUInt16(provider As IFormatProvider) As UInt16 Implements IConvertible.ToUInt16
      If temp < UInt16.MinValue Or temp > UInt16.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the UInt16 data type.", temp))
      End If
      Return CUShort(Math.Round(temp))
   End Function
   
   Public Function ToUInt32(provider As IFormatProvider) As UInt32 Implements IConvertible.ToUInt32
      If temp < UInt32.MinValue Or temp > UInt32.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the UInt32 data type.", temp))
      End If
      Return CUInt(Math.Round(temp))
   End Function
   
   Public Function ToUInt64(provider As IFormatProvider) As UInt64 Implements IConvertible.ToUInt64
      If temp < UInt64.MinValue Or temp > UInt64.MaxValue Then
         Throw New OverflowException(String.Format("{0} is out of range of the UInt64 data type.", temp))
      End If
      Return CULng(Math.Round(temp))
   End Function
End Class

Public Class TemperatureCelsius : Inherits Temperature : Implements IConvertible
   Public Sub New(value As Decimal)
      MyBase.New(value)
   End Sub

   ' Override ToString methods.
   Public Overrides Function ToString() As String
      Return Me.ToString(Nothing)
   End Function

   Public Overrides Function ToString(provider As IFormatProvider ) As String
      Return temp.ToString(provider) + "°C" 
   End Function
   
  ' If conversionType is a implemented by another IConvertible method, call it.
   Public Overrides Function ToType(conversionType As Type, provider As IFormatProvider) As Object
      ' For non-objects, call base method.
      If Type.GetTypeCode(conversionType) <> TypeCode.Object Then
         Return MyBase.ToType(conversionType, provider)
      Else   
         If conversionType.Equals(GetType(TemperatureCelsius)) Then
            Return Me
         ElseIf conversionType.Equals(GetType(TemperatureFahrenheit))
            Return New TemperatureFahrenheit(CDec(Me.temp * 9 / 5 + 32))
         ' Unspecified object type: throw an InvalidCastException.
         Else
            Throw New InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", _ 
                                           conversionType.Name))
         End If
      End If                                  
   End Function
End Class

Public Class TemperatureFahrenheit : Inherits Temperature : Implements IConvertible
   Public Sub New(value As Decimal)
      MyBase.New(value)
   End Sub
   
   ' Override ToString methods.
   Public Overrides Function ToString() As String
      Return Me.ToString(Nothing)
   End Function

   Public Overrides Function ToString(provider As IFormatProvider ) As String
      Return temp.ToString(provider) + "°F" 
   End Function
   
   Public Overrides Function ToType(conversionType As Type, provider As IFormatProvider) As Object
      ' For non-objects, call base methood.
      If Type.GetTypeCode(conversionType) <> TypeCode.Object Then
         Return MyBase.ToType(conversionType, provider)
      Else   
         ' Handle conversion between derived classes.
         If conversionType.Equals(GetType(TemperatureFahrenheit)) Then 
            Return Me
         ElseIf conversionType.Equals(GetType(TemperatureCelsius))
            Return New TemperatureCelsius(CDec((MyBase.temp - 32) * 5 / 9))
         ' Unspecified object type: throw an InvalidCastException.
         Else
            Throw New InvalidCastException(String.Format("Cannot convert from Temperature to {0}.", _
                                           conversionType.Name))
         End If
      End If                                  
   End Function
End Class   

下列範例說明對這些 IConvertible 實作的多個呼叫,以將 TemperatureCelsius 物件轉換為 TemperatureFahrenheit 物件,反之亦然。The following example illustrates several calls to these IConvertible implementations to convert TemperatureCelsius objects to TemperatureFahrenheit objects and vice versa.

TemperatureCelsius tempC1 = new TemperatureCelsius(0);
TemperatureFahrenheit tempF1 = (TemperatureFahrenheit) Convert.ChangeType(tempC1, typeof(TemperatureFahrenheit), null);
Console.WriteLine("{0} equals {1}.", tempC1, tempF1);
TemperatureCelsius tempC2 = (TemperatureCelsius) Convert.ChangeType(tempC1, typeof(TemperatureCelsius), null);
Console.WriteLine("{0} equals {1}.", tempC1, tempC2);
TemperatureFahrenheit tempF2 = new TemperatureFahrenheit(212);
TemperatureCelsius tempC3 = (TemperatureCelsius) Convert.ChangeType(tempF2, typeof(TemperatureCelsius), null);
Console.WriteLine("{0} equals {1}.", tempF2, tempC3);
TemperatureFahrenheit tempF3 = (TemperatureFahrenheit) Convert.ChangeType(tempF2, typeof(TemperatureFahrenheit), null);
Console.WriteLine("{0} equals {1}.", tempF2, tempF3);
// The example displays the following output:
//       0°C equals 32°F.
//       0°C equals 0°C.
//       212°F equals 100°C.
//       212°F equals 212°F.
Dim tempC1 As New TemperatureCelsius(0)
Dim tempF1 As TemperatureFahrenheit = CType(Convert.ChangeType(tempC1, GetType(TemperatureFahrenheit), Nothing), TemperatureFahrenheit)
Console.WriteLine("{0} equals {1}.", tempC1, tempF1) 
Dim tempC2 As TemperatureCelsius = CType(Convert.ChangeType(tempC1, GetType(TemperatureCelsius), Nothing), TemperatureCelsius)
Console.WriteLine("{0} equals {1}.", tempC1, tempC2) 
Dim tempF2 As New TemperatureFahrenheit(212)
Dim tempC3 As TEmperatureCelsius = CType(Convert.ChangeType(tempF2, GEtType(TemperatureCelsius), Nothing), TemperatureCelsius)
Console.WriteLine("{0} equals {1}.", tempF2, tempC3) 
Dim tempF3 As TemperatureFahrenheit = CType(Convert.ChangeType(tempF2, GetType(TemperatureFahrenheit), Nothing), TemperatureFahrenheit)
Console.WriteLine("{0} equals {1}.", tempF2, tempF3)
' The example displays the following output:
'       0°C equals 32°F.
'       0°C equals 0°C.
'       212°F equals 100°C.
'       212°F equals 212°F.      

TypeConverter 類別The TypeConverter Class

.NET Framework 也可讓您延伸 System.ComponentModel.TypeConverter 類別,並透過 System.ComponentModel.TypeConverterAttribute 屬性來建立類型轉換子與類型之間的關聯,以定義自訂類型的類型轉換子。The .NET Framework also allows you to define a type converter for a custom type by extending the System.ComponentModel.TypeConverter class and associating the type converter with the type through a System.ComponentModel.TypeConverterAttribute attribute. 下表特別強調這種作法與實作自訂類型之 IConvertible 介面的差異。The following table highlights the differences between this approach and implementing the IConvertible interface for a custom type.

注意

只要自訂類型有為其定義的類型轉換子,即會提供設計階段支援給自訂類型。Design-time support can be provided for a custom type only if it has a type converter defined for it.

使用 TypeConverter 的轉換Conversion using TypeConverter 使用 IConvertible 的轉換Conversion using IConvertible
是從 TypeConverter 衍生另外一個類別,以針對自訂類型來實作。Is implemented for a custom type by deriving a separate class from TypeConverter. 透過套用 TypeConverterAttribute 屬性,將這個衍生類別與自訂類型建立關聯。This derived class is associated with the custom type by applying a TypeConverterAttribute attribute. 是由自訂類型所實作來執行轉換。Is implemented by a custom type to perform conversion. 該類型的使用者在該類型上叫用 IConvertible 轉換方法。A user of the type invokes an IConvertible conversion method on the type.
可以在設計階段和在執行階段兩處使用。Can be used both at design time and at run time. 只能在執行階段使用。Can be used only at run time.
使用反映,因此,速度比 IConvertible 所啟用的轉換還要慢。Uses reflection; therefore, is slower than conversion enabled by IConvertible. 不使用反映。Does not use reflection.
允許在自訂類型與其他資料類型之間的雙向類型轉換。Allows two-way type conversions from the custom type to other data types, and from other data types to the custom type. 例如,針對 TypeConverter 所定義的 MyType 允許從 MyType 轉換為 String,也允許從 String 轉換為 MyTypeFor example, a TypeConverter defined for MyType allows conversions from MyType to String, and from String to MyType. 允許從自訂類型轉換為其他資料類型,但不允許從其他資料類型轉換為自訂類型。Allows conversion from a custom type to other data types, but not from other data types to the custom type.

如需使用類型轉換子執行轉換的詳細資訊,請參閱 System.ComponentModel.TypeConverterFor more information about using type converters to perform conversions, see System.ComponentModel.TypeConverter.

請參閱See also