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

C# 擴展方法進階實戰:Enumerable.Cast<T> 實戰應用指南

     編輯:關於C#

前言

Enumerable.Cast<T>() 將非泛型 IEnumerable 轉為泛型 IEnumerable<T>,解鎖 LINQ 查詢能力。許多開發者以為它只用於 ArrayList,實則廣泛適用於 WinForms/WPF 控制項集合、舊版 API 回傳值等場景。

核心適用場景

1. WinForms 控制項集合

// ListBox/ComboBox Items
var employees = listBox.Items.Cast<Employee>();
var count = employees.Count();
var hasBob = employees.Any(e => e.FirstName == "Bob");

// DataGridView 選取列/欄/儲存格
var selectedRows = dataGridView.SelectedRows.Cast<DataGridViewRow>();
var selectedCols = dataGridView.SelectedColumns.Cast<DataGridViewColumn>();
var selectedCells = dataGridView.SelectedCells.Cast<DataGridViewCell>();

// TreeNode 集合
var allNodes = treeView1.Nodes.Cast<TreeNode>();
var recursiveNodes = treeNode.Nodes.Cast<TreeNode>();

// 任意控制項的 Controls 集合
var allControls = this.Controls.Cast<Control>();
var textBoxes = this.Controls.Cast<Control>().OfType<TextBox>();

2. 實戰查詢範例

// 計算選取員工平均年齡
int avgAge = dataGridView.SelectedRows
    .Cast<DataGridViewRow>()
    .Select(r => (Employee)r.DataBoundItem)
    .Average(e => e.Age);

// 統計選取員工所在城市 (去重)
var cities = dataGridView.SelectedRows
    .Cast<DataGridViewRow>()
    .Select(r => (Employee)r.DataBoundItem)
    .Select(e => e.City)
    .Distinct()
    .ToArray();

繼承關係下的型別轉換


public class A { }
public class B : A { }

// 子類陣列 -> 父類陣列 (安全)
B[] bArray = { new B(), new B() };
A[] aArray = bArray.Cast<A>().ToArray(); // OK

// 父類陣列 -> 子類陣列 (風險)
A[] mixed = { new A(), new A(), new B() };
// B[] bArray2 = mixed.Cast<B>().ToArray(); // 執行期拋出 InvalidCastException

// 解決方案:使用 OfType<T> 過濾兼容型別
B[] bArray2 = mixed.OfType<B>().ToArray(); // 僅保留 B 實例,安全無例外

Cast<T> vs OfType<T> vs 轉型運算子

操作行為適用場景
Cast<T>()強制轉型,失敗拋例外確定所有元素皆為 T 或其衍生類
OfType<T>()過濾並轉型,忽略不匹配元素混合型別集合,只需特定型別
(T)item編譯期/執行期強制轉型單一元素確定型別

值型別轉換限制


// 基本型別轉換
int i = (int)1.5;        // OK: 隱含/明確轉換
double d = 10;           // OK

// 但 Cast<T> 不支援值型別之間的數值轉換!
int[] ints = { 1, 2, 3 };
// double[] doubles = ints.Cast<double>().ToArray(); // 執行期失敗!

// 原因:Cast 內部執行 (T)enumerator.Current,值型別需拆箱為確切型別才能轉型
// 解決:使用 Select 轉換
double[] doubles = ints.Select(x => (double)x).ToArray(); // OK

內部實現原理

Cast<T> 使用 CastIterator 實現,核心邏輯:

// 簡化版
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
    foreach (object obj in source)
        yield return (TResult)obj; // 直接強制轉型
}

這解釋了為何值型別數值轉換失敗:object 裝箱後為 int,無法直接拆箱為 double。

最佳實務建議

  1. 優先使用泛型集合:新代碼避免非泛型集合,從源頭杜絕 Cast 需求。
  2. 控制項集合必用 Cast:WinForms/WebForms 控制項集合為非泛型設計,Cast 是啟用 LINQ 的標準做法。
  3. 混合型別用 OfType:不確定元素型別純度時,OfType<T>() 更安全。
  4. 值型別轉換用 Select:ints.Select(x => (double)x) 替代 Cast<double>()。

結語

Cast<T> 是連結舊式非泛型 API 與現代 LINQ 生態的關鍵橋樑。掌握其適用邊界、轉換規則與替代方案,能讓你在維護舊專案、操作 UI 控制項樹時游刃有餘。

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