首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 顯式類型轉換完整指南:強制轉型規則、數值/列舉/參考轉換與溢位檢查機制

     編輯:關於C#

顯式類型轉換 (強制轉型) 是開發者明確指示編譯器進行型別轉換的機制,語法為 (T)expr。它包含所有隱含轉換,並擴展至可能遺失資訊、拋出例外或需執行時期檢查的轉換。深入理解各類轉換規則與邊界條件,對編寫健壯程式碼至關重要。

核心語法與語意

(目標類型)運算式
// 語意:嘗試將運算式結果轉換為目標類型
// 可能結果:成功、資訊遺失、溢位例外、InvalidCastException、NullReferenceException

與隱含轉換關係

  • 所有隱含轉換均可寫為顯式形式:long l = (long)5; (合法但多餘)
  • 顯式轉換是隱含轉換的超集
  • 編譯器允許冗餘顯式轉換 (可讀性/文檔目的)

三大顯式轉換類別

1. 顯式數值轉換

在無隱含轉換的數值類型間轉換:

來源 → 目標範例風險
較大整數 → 較小整數long → int, int → short, int → byte截斷高位、溢位
有號 → 無號 / 無號 → 有號int → uint, uint → int, long → ulong符號位重新解讀、溢位
浮點數 → 整數double → int, float → long, decimal → int截斷小數部、溢位、NaN/Infinity 處理
高精度 → 低精度浮點數double → float, decimal → double, decimal → float精度遺失、溢位為 Infinity
字元 → 整數char → int, char → shortUnicode 碼位值、可能溢位

轉換規則詳解

// 1. 整數 → 整數:截斷高位 (unchecked) / 例外 (checked)
int i = 300;
byte b = (byte)i;     // 44 (300 % 256)
checked { byte c = (byte)i; } // OverflowException

// 2. 浮點數 → 整數:向零截斷小數部
double d = 3.9;
int i2 = (int)d;      // 3
double neg = -3.9;
int i3 = (int)neg;    // -3 (向零,非向下)

// 溢位:超出目標範圍 → OverflowException (checked) / 未定義 (unchecked)
double huge = 1e20;
int crash = (int)huge; // OverflowException (checked)

// NaN/Infinity → 整數
(int)double.NaN        // 0 (未定義行為,實際常為 0)
(int)double.PositiveInfinity // 未定義/例外

// 3. double → float:IEEE 754 捨入最近
double precise = 1.123456789012345;
float f = (float)precise; // 1.1234568f (精度遺失)

// 4. decimal → float/double:可能溢位為 Infinity
decimal maxDec = decimal.MaxValue;
double d2 = (double)maxDec; // 7.9228162514264338E+28 (在 double 範圍內)
float f2 = (float)maxDec;   // Infinity (超出 float 範圍)

// 5. float/double → decimal:精度限制 28-29 位
double pi = Math.PI;
decimal decPi = (decimal)pi; // 3.14159265358979m (精度截斷)

// 6. decimal → 整數:向零截斷
decimal dec = 10.9m;
int i4 = (int)dec; // 10

2. 顯式列舉轉換

列舉與整數/其他列舉間轉換:

enum Color : int { Red = 1, Green = 2, Blue = 4 }
enum Priority { Low, Medium, High } // 底層 int

// 整數 → 列舉
Color c1 = (Color)2;        // Green
Color c2 = (Color)99;       // 99 (無對應成員,合法但危險)

// 列舉 → 整數
int val = (int)Color.Red;   // 1

// 列舉 → 列舉 (不同底層類型需相容)
Priority p = (Priority)Color.Red; // Priority.Low (值 1)

// 底層機制:轉換為底層類型 → 目標類型
// Color (int) → int → Priority (int)

Flags 列舉轉換陷阱

[Flags] enum Perm { Read = 1, Write = 2, Exec = 4 }
Perm p = (Perm)3; // Read | Write (值 3)
// 注意:非 Flags 列舉轉換整數無語意檢查

3. 顯式參考轉換

參考類型間、介面間、陣列共變數/逆變數轉換:

適用場景

轉換類型範例執行時期檢查
衍生類別 → 基底類別/介面Derived → Base, Derived → IInterface隱含轉換 (無需顯式,但可寫)
基底類別 → 衍生類別Base → Derived是 (可能 InvalidCastException)
介面 → 實作類別IInterface → Class是
介面 → 介面 (非繼承)I1 → I2是
陣列共變數string[] → object[]隱含 (但寫入檢查元素型別)
陣列逆變數object[] → string[]是 (執行時期檢查)
委派逆變數/共變數Action<object> → Action<string>是
object/介面 → 實質類別object → StringBuilder是

關鍵規則

// 來源必須為 null 或可轉換為目標類型
object obj = "hello";
StringBuilder sb = (StringBuilder)obj; // InvalidCastException: 字串非 StringBuilder

object obj2 = new StringBuilder();
StringBuilder sb2 = (StringBuilder)obj2; // 成功

// null 總是轉換成功
object n = null;
string s = (string)n; // null (不拋出例外)

// 參考轉換不改變物件身分,只改變編譯時期型別
// 同一物件,不同「視角」

陣列轉換細節

// 共變數:衍生元素 → 基底元素 (唯讀安全)
string[] strings = { "a", "b" };
object[] objects = strings; // 隱含轉換,可寫 (object[])strings

// 逆變數:基底元素 → 衍生元素 (寫入危險)
object[] objs = { "a", "b" };
string[] strs = (string[])objs; // 成功 (元素確實為 string)
objs[0] = 123; // ArrayTypeMismatchException (執行時期檢查)

// 維度必須相同,元素類型皆為參考類型
// int[] → object[] 不允許 (int 為值類型)

溢位檢查語境控制

語境關鍵字整數溢位行為浮點數/decimal
預設(無 / unchecked)環繞 (截斷高位)IEEE 754 / 例外
檢查checkedOverflowException不影響 (浮點數無溢位概念,decimal 總檢查)
常數運算式(編譯器)永遠檢查 (編譯錯誤)編譯時期計算
// 區塊範圍
checked 
{
    int a = int.MaxValue;
    int b = a + 1; // OverflowException
}

// 運算式範圍
int c = checked(int.MaxValue + 1); // OverflowException

// 關閉檢查 (預設)
unchecked 
{
    int d = int.MaxValue + 1; // 環繞為 int.MinValue
}

使用者定義轉換運算子

public readonly struct Celsius
{
    public double Value { get; }
    
    // 隱含轉換:double → Celsius (安全、無遺失)
    public static implicit operator Celsius(double d) 
        => new Celsius { Value = d };
    
    // 顯式轉換:Celsius → double (可能遺失單位資訊)
    public static explicit operator double(Celsius c) 
        => c.Value;
    
    // 顯式轉換:Celsius → Fahrenheit (領域轉換)
    public static explicit operator Fahrenheit(Celsius c) 
        => new Fahrenheit { Value = c.Value * 9/5 + 32 };
}

最佳實踐總結

  1. 數值縮小轉換必用 checked — 或 TryConvert (Core 2.0+) 避免靜默資料遺失
  2. 浮點數 → 整數向零截斷 — 非四捨五入,非向下取整
  3. 參考轉換失敗拋出 InvalidCastException — 使用 as 或 is 模式避免例外
  4. 陣列逆變數寫入會觸發 ArrayTypeMismatchException — 設計時避免
  5. 列舉轉換整數無語意檢查 — Flags 列舉除外,驗證 Enum.IsDefined
  6. 自訂轉換運算子語意明確 — 隱含 = 安全無遺失,顯式 = 可能遺失/領域轉換
  7. 避免在熱路徑頻繁轉換 — 尤其參考轉換與 decimal 雙向轉換

精通顯式轉換的分類規則、溢位語境與執行時期檢查機制,能在型別安全與開發效率間取得最佳平衡。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved