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

LINQ 查詢非泛型集合的三種實用技巧

     編輯:關於.NET

LINQ 的強大之處在於能夠輕鬆查詢實作 IEnumerable<T> 介面的泛型集合。然而,像 ArrayList 這類非泛型集合並未實作該介面,直接套用 LINQ 查詢會導致編譯錯誤。這並不意味著我們必須放棄 LINQ 的優雅語法,只要掌握幾個關鍵技巧,即可讓非泛型集合也能享受 LINQ 的查詢能力。

問題重現

假設我們有一個儲存 Cars 物件的 ArrayList,嘗試直接使用 LINQ 查詢 BMW 車款:

ArrayList carList = new ArrayList();
carList.Add(new Cars { CarMake = "BMW", CarModel = "BMW Art", Year = 1978 });
carList.Add(new Cars { CarMake = "BMW", CarModel = "Coupe", Year = 1982 });
carList.Add(new Cars { CarMake = "Renault", CarModel = "Alpine", Year = 1972 });
carList.Add(new Cars { CarMake = "Porsche", CarModel = "Maisto", Year = 1976 });

// 編譯錯誤:ArrayList 未實作 IEnumerable<T>
var carQuery = from car in carList
               where car.CarMake == "BMW"
               select car;

編譯器會報錯,因為 ArrayList 僅實作 IEnumerable(非泛型版本),無法推斷元素型別。

解決方案一:查詢運算式中顯式指定型別

在 from 子句中為範圍變數明確宣告型別,編譯器會自動插入轉型操作:

// C#
var cc = from Cars car in carList
         where car.CarMake == "BMW"
         select car;

// VB.NET
Dim cc = From car As Cars In carList
         Where car.CarMake = "BMW"
         Select car

這相當於對集合中的每個物件執行 (Cars)car 轉型,若集合包含非 Cars 型別物件,執行時會拋出 InvalidCastException。

解決方案二:使用 Cast<T> 方法

Cast<T>() 擴充方法可將實作 IEnumerable 的非泛型集合轉換為 IEnumerable<T>:

// C#
var cc1 = from car in carList.Cast<Cars>()
          where car.CarMake == "BMW"
          select car;

// VB.NET
Dim cc1 = From car In carList.Cast(Of Cars)()
          Where car.CarMake = "BMW"
          Select car

此方法同樣會對所有元素嘗試轉型,遇到不相容型別時拋出例外。

解決方案三:使用 OfType<T> 方法(推薦)

OfType<T>() 會篩選集合中指定型別的元素,自動略過不相容物件,更加安全:

// C#
var cc2 = from car in carList.OfType<Cars>()
          where car.CarMake == "BMW"
          select car;

// VB.NET
Dim cc2 = From car In carList.OfType(Of Cars)()
          Where car.CarMake = "BMW"
          Select car

若集合混雜不同型別物件,OfType 僅返回符合條件的元素,不會拋出例外,是處理非泛型集合最穩健的選擇。

完整程式碼範例

以下整合三種寫法的完整 C# 範例:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace QueryArraylistWithLINQ
{
    public class Cars
    {
        public string CarMake { get; set; }
        public string CarModel { get; set; }
        public int Year { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ArrayList carList = new ArrayList();
            carList.Add(new Cars { CarMake = "BMW", CarModel = "BMW Art", Year = 1978 });
            carList.Add(new Cars { CarMake = "BMW", CarModel = "Coupe", Year = 1982 });
            carList.Add(new Cars { CarMake = "Renault", CarModel = "Alpine", Year = 1972 });
            carList.Add(new Cars { CarMake = "Porsche", CarModel = "Maisto", Year = 1976 });

            // 方法一:顯式指定型別
            var cc = from Cars car in carList
                     where car.CarMake == "BMW"
                     select car;

            // 方法二:Cast
            var cc1 = from car in carList.Cast<Cars>()
                      where car.CarMake == "BMW"
                      select car;

            // 方法三:OfType(推薦)
            var cc2 = from car in carList.OfType<Cars>()
                      where car.CarMake == "BMW"
                      select car;

            // 輸出結果
            foreach (Cars c in cc1)
                Console.WriteLine($"{c.CarMake}-{c.CarModel}");

            Console.ReadLine();
        }
    }
}

總結比較

方法語法適用場景風險
顯式型別from Cars car in list確定集合元素型別單一型別不符時拋出例外
Cast<T>()list.Cast<Cars>()需轉換為泛型集合進一步操作型別不符時拋出例外
OfType<T>()list.OfType<Cars>()集合可能包含混雜型別安全篩選,無例外風險

實務上建議優先使用 OfType<T>(),既能啟用 LINQ 查詢,又能優雅處理型別不匹配情況,程式碼更健壯。

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