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

C# 型別轉換完整指南:隱含/顯式轉換、轉換方法、模式比對、使用者定義轉換與最佳實踐

     編輯:C# 入門

C# 型別轉換完整指南:隱含/顯式轉換、轉換方法、模式比對、使用者定義轉換與最佳實踐

型別轉換 是將一種型別的值轉換為另一種型別。C# 提供隱含轉換 (安全、無資料遺失)、顯式轉換 (需轉型運算子、可能遺失資料/拋例外)、使用者定義轉換、轉換輔助類別、模式比對 等多種機制。正確選擇轉換方式能確保型別安全、避免執行期錯誤。

隱含轉換:安全、自動

編譯器自動執行,保證不遺失資訊、不拋例外:

// 數值擴展
int i = 42;
long l = i;        // int -> long
float f = i;       // int -> float (可能精度遺失,但 C# 允許)
double d = f;      // float -> double
decimal m = i;     // int -> decimal

// 衍生類 -> 基底類/介面
string s = "hello";
object o = s;      // 參考轉換
IEnumerable en = new List(); // 介面轉換

// 常數縮小 (編譯期已知值在目標範圍)
byte b = 100;      // int 常數 -> byte
const int Small = 200;
byte b2 = Small;   // OK
// int runtime = 200; byte b3 = runtime; // 錯誤:非常數需顯式

顯式轉換:需轉型運算子

可能遺失資料或執行期失敗,開發者承擔風險:

// 數值縮小
double d = 3.14159;
int i = (int)d;     // 3 (截斷小數)
long big = 5000000000;
int small = (int)big; // 截斷高位,結果不可預期

// 基底類 -> 衍生類 (下行轉換)
object obj = "hello";
string str = (string)obj; // 成功
// int num = (int)obj;     // InvalidCastException

// 介面 -> 實作類
IEnumerable en = new List();
var list = (List)en; // 成功 (若實際為 List)

安全下行轉換模式

// 1. is 型別模式 (C# 7+)
if (obj is string s) { Console.WriteLine(s.Length); }

// 2. as 運算子 (僅參考/可為 Null 型別)
string s2 = obj as string; // 失敗回傳 null
if (s2 != null) { /* ... */ }

// 3. 模式比對 switch
var result = obj switch {
    string s => s.Length,
    int i => i * 2,
    _ => 0
};

使用者定義轉換

為自訂型別定義隱含/顯式轉換運算子:

public readonly struct Temperature {
    public double Celsius { get; }
    public Temperature(double c) => Celsius = c;
    
    // 隱含轉換:double -> Temperature (安全)
    public static implicit operator Temperature(double c) => new Temperature(c);
    
    // 顯式轉換:Temperature -> double (可能遺失單位資訊)
    public static explicit operator double(Temperature t) => t.Celsius;
    
    // 另一個結構體轉換
    public static implicit operator Temperature(Fahrenheit f) 
        => new Temperature((f.Value - 32) * 5/9);
}

public readonly struct Fahrenheit {
    public double Value { get; }
    public Fahrenheit(double v) => Value = v;
}

// 使用
Temperature t = 25.0;           // 隱含:double -> Temperature
double c = (double)t;           // 顯式:Temperature -> double
Fahrenheit f = new(98.6);
Temperature t2 = f;             // 隱含:Fahrenheit -> Temperature

轉換運算子規則

  • 必須 public static
  • 來源或目標型別必須為定義型別
  • 不可在同一方向定義隱含和顯式
  • 隱含轉換不可拋例外、不可遺失資訊
  • 避免轉換鏈模稜兩可

轉換輔助類別

System.Convert:基礎型別轉換

int i = Convert.ToInt32("42");        // 字串 -> int
double d = Convert.ToDouble("3.14");  // 字串 -> double
string s = Convert.ToString(42);      // int -> 字串
bool b = Convert.ToBoolean(1);        // 非零 -> true
DateTime dt = Convert.ToDateTime("2024-01-01");

// 溢位檢查:超出目標範圍拋 OverflowException
byte bb = Convert.ToByte(300); // 例外

Parse / TryParse:字串解析

int i = int.Parse("42");              // 失敗拋 FormatException/OverflowException
bool ok = int.TryParse("42", out int j); // 不拋例外,回傳 bool

// 格式化選項
int hex = int.Parse("FF", NumberStyles.HexNumber); // 255
var styles = NumberStyles.AllowCurrencySymbol | NumberStyles.AllowThousands;
decimal price = decimal.Parse("$1,234.56", styles);

TypeConverter / JsonSerializer / XmlSerializer

複雜物件序列化/反序列化、設計工具整合、設定綁定。

模式比對轉換

// C# 7+ is 型別模式宣告
if (input is int i) { /* i 為 int */ }
if (input is string { Length: > 10 } s) { /* s 為長字串 */ }

// switch 運算式
object Convert(object input) => input switch {
    int i => i.ToString(),
    double d => d.ToString("F2"),
    DateTime dt => dt.ToString("o"),
    IFormattable f => f.ToString(null, CultureInfo.CurrentCulture),
    _ => input?.ToString() ?? ""
};

特殊轉換場景

裝箱 / 解箱

int i = 42;
object o = i;        // 裝箱:配置物件、複製值
int j = (int)o;      // 解箱:驗證型別、複製值

// 避免裝箱:用泛型、介面約束
void Process(T value) where T : struct { }

動態轉換

dynamic d = "hello";
int len = (int)d.Length; // 執行期繫結,失敗拋 RuntimeBinderException

指標轉換

unsafe {
    int i = 42;
    int* p = &i;
    void* vp = p;           // 隱含 void*
    int* p2 = (int*)vp;     // 顯式回 int*
    long addr = (long)p;    // 指標 -> 整數
    int* p3 = (int*)addr;   // 整數 -> 指標
}

最佳實踐

  • 優先隱含轉換:讓編譯器自動處理安全轉換。
  • 顯式轉換用模式比對:is/as/switch 替代 (Type)x,避免 InvalidCastException。
  • 字串解析用 TryParse:避免例外控制流程,效能更好。
  • 定義轉換運算子謹慎:隱含轉換必須真正安全、無副作用;顯式轉換文件化資料遺失風險。
  • 避免裝箱:熱路徑用泛型、Span<T>、實值型別介面約束。
  • 跨層轉換集中管理:DTO <-> Entity、API Model <-> Domain Model 用 Mapper (AutoMapper/Mapster/手寫)。

常見問題 FAQ

Q: as 可以用於實值型別嗎?

A: 不能直接用於非可為 Null 實值型別。可用 int?:int? i = obj as int?;。

Q: Convert.ToInt32 vs int.Parse 差異?

A: Convert 接受 null 回傳 0,Parse 拋 ArgumentNullException。Convert 支援更多型別來源。

Q: 為什麼不能隱含轉換 double -> int?

A: 會遺失小數精度、可能溢位。C# 要求開發者明確承擔風險 (顯式轉換)。

Q: 使用者定義轉換會參與多載解析嗎?

A: 會。隱含轉換優先序高於顯式。模稜兩可時編譯器報錯。

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