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

C# 顯式參考轉換深度解析:繼承層級、介面轉換、陣列共變數逆變數與執行時期檢查機制

     編輯:關於C#

顯式參考轉換 ((T)expr) 是在參考類型層級結構中進行向下/橫向轉換的機制,編譯器允許但執行時期會驗證物件實際類型相容性。理解其適用場景、陣列/委派變異規則與失敗模式,對建立型別安全的多型系統至關重要。

核心語意與分類

(目標類型)運算式
// 編譯時期:允許潛在相容的參考類型轉換
// 執行時期:檢查實際物件是否為目標類型或其衍生類別
// 成功:回傳同一物件參考 (型別視角改變)
// 失敗:拋出 InvalidCastException
// null:永遠成功,回傳 null

七大顯式參考轉換類別

類別來源 → 目標條件執行檢查範例
1. 物件 → 任意參考類型object → TT 為參考類型是object o = "hi"; (string)o
2. 基底類別 → 衍生類別Base → Derived衍生自 Base是Animal a = new Dog(); (Dog)a
3. 非密封基底類別 → 介面Base → IInterfaceBase 未實作 IInterface,且非 sealed是class Base {} (ICloneable)new Base()
4. 介面 → 非密封類別IInterface → ClassClass 未實作 IInterface,且非 sealed是ICloneable c = ...; (MyClass)c
5. 介面 → 介面 (非繼承)I1 → I2I1 非 I2 子介面是IEnumerable e = ...; (IList)e
6. 陣列轉換S[] → T[]同維度、元素皆參考類型、元素間有顯式參考轉換是 (含元素檢查)object[] → string[]
7. 系統類別轉換Array → T[], Delegate → TDelegate, ICloneable → T[]/TDelegate特定系統類別是Array arr = ...; (int[])arr

繼承層級轉換實戰

向上轉換 (隱含,但可顯式寫)

class Animal { }
class Dog : Animal { }
class Cat : Animal { }

Animal a = new Dog();        // 隱含
Animal a2 = (Animal)new Dog(); // 顯式 (多餘但合法)

向下轉換 (必須顯式,執行時期檢查)

Animal a = new Dog();
Dog d = (Dog)a;      // 成功:a 實際為 Dog

Animal a2 = new Cat();
Dog d2 = (Dog)a2;    // InvalidCastException:a2 實際為 Cat

// 防禦性模式
if (a is Dog dog) { /* 使用 dog */ }
var dog2 = a as Dog; // null 安全

橫向轉換 (同層級兄弟類別)

Dog d = new Dog();
Cat c = (Cat)(Animal)d; // InvalidCastException
// 必須先向上到共同基底,再向下

介面轉換矩陣

interface ISerializable { }
interface ICloneable { }
class Document : ISerializable { }
class SerializableDoc : Document, ICloneable { }

ISerializable ser = new Document();
ICloneable clone = (ICloneable)ser; // InvalidCastException (Document 未實作 ICloneable)

ISerializable ser2 = new SerializableDoc();
ICloneable clone2 = (ICloneable)ser2; // 成功 (實際物件實作 ICloneable)

// 介面 → 類別 (類別未實作介面但非 sealed)
ICloneable c = new SerializableDoc();
Document doc = (Document)c; // 成功 (SerializableDoc 繼承 Document)

// 介面 → 介面 (非繼承關係)
IEnumerable enumObj = new List();
IList list = (IList)enumObj; // 成功 (List 實作 IList)

陣列轉換:共變數與逆變數

共變數 (向上,隱含安全 — 唯讀場景)

string[] strings = { "a", "b" };
object[] objects = strings; // 隱含轉換 (編譯器允許)

// 風險:寫入非預期類型
objects[0] = 123; // ArrayTypeMismatchException (執行時期檢查元素型別)
// 共變數安全前提:僅讀取元素

逆變數 (向下,必須顯式,寫入危險)

object[] objects = { "a", "b" }; // 實際元素為 string
string[] strings = (string[])objects; // 顯式轉換成功 (元素確實相容)

// 但若元素不相容
object[] objects2 = { "a", 123 };
string[] strings2 = (string[])objects2; // InvalidCastException (執行時期檢查)

// 規則總結
// 1. 維度相同
// 2. 元素類型皆為參考類型 (值類型陣列無共變數/逆變數)
// 3. 元素類型間有參考轉換關係 (隱含/顯式)
// 4. 執行時期檢查實際元素型別

多維陣列 / 交錯陣列

// 多維陣列:同規則,維度數必須完全相同
string[,] matrix2 = new string[2,2];
object[,] objMatrix = matrix2; // 共變數

// 交錯陣列:外層陣列元素為陣列參考
string[][] jagged = new string[2][];
object[][] objJagged = jagged; // 共變數 (外層元素 string[] → object[])

委派轉換:逆變數/共變數 (C# 4.0+)

// 委派參數逆變數:輸入類型可接受基底類別
Action actObj = o => Console.WriteLine(o);
Action actStr = (Action)actObj; // 顯式轉換成功
// actStr("hello") → actObj("hello") 安全 (string 是 object)

// 委派回傳值共變數:輸出類型可為衍生類別
Func funcStr = () => "hello";
Func funcObj = (Func)funcStr; // 顯式轉換成功
// object o = funcObj() → 實際回傳 string 安全

// 完整範例
delegate TResult Converter(TInput input);

Converter conv1 = ...;
Converter conv2 = (Converter)conv1; // 合法 (逆變數 in, 共變數 out)

系統類別特殊轉換

// Array → 具體陣列
Array arr = new int[10];
int[] intArr = (int[])arr; // 成功

// Delegate → 具體委派
Delegate del = new Action(() => { });
Action act = (Action)del; // 成功

// ICloneable → 陣列/委派 (歷史遺留)
ICloneable clone = new int[5];
int[] arr2 = (int[])clone; // 成功 (陣列實作 ICloneable)

執行時期檢查機制與效能

  • 編譯為 castclass IL 指令
  • 執行時期:檢查物件 TypeHandle 是否為目標類型或其子類型
  • null 檢查:快速路徑,直接回傳 null
  • 效能:單次型別比較,極快 (納秒級),但失敗拋出例外成本高

最佳實踐策略

  1. 優先使用 is 模式比對 — if (obj is Dog dog) 單次檢查、零例外、範圍安全
  2. 次選 as + null 檢查 — var dog = obj as Dog; if (dog != null) 避免例外開銷
  3. 確定成功時用顯式轉換 — 失敗即 Bug,拋出例外暴露問題 (如序列化還原)
  4. 避免陣列逆變數寫入 — 設計 API 使用 IReadOnlyList<T> 或不可變集合
  5. 委派變異用 in/out 標記 — 編譯器靜態驗證,無執行開銷
  6. 介面轉換文檔化預期實作類型 — 減少橫向轉換需求

常見錯誤模式

// 1. 忽略 null 檢查直接轉換
var s = (string)obj; // obj 為 null 時回傳 null,但後續 s.Length 拋出 NRE

// 2. 陣列逆變數後寫入
object[] arr = { "a" };
string[] strs = (string[])arr;
strs[0] = "b"; // 成功
arr[0] = 123;  // ArrayTypeMismatchException (延遲炸彈)

// 3. 介面轉換假設實作
IEnumerable e = GetEnumerable();
IList list = (IList)e; // 可能失敗,應用 is/as

// 4. 密封類別介面轉換
sealed class SealedClass { }
ICloneable c = (ICloneable)new SealedClass(); // 編譯錯誤 (密封類別無顯式介面轉換)

精通顯式參考轉換的分類規則、執行時期檢查語意與現代替代方案,能構建更安全、高效且可維護的多型系統。

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