我們來看看以下程序吧:
01: using System; 02: using System.Data; 03: using System.Linq; 04: 05: namespace Skyiv.Ben 06: { 07: class Program 08: { 09: static void Main() 10: { 11: var dt = new DataTable(); 12: dt.Rows.Add(); 13: foreach (var row in dt.Select()) 14: { 15: Console.WriteLine(row.GetType()); 16: Console.WriteLine(row.RowState); 17: } 18: } 19: } 20: }
上述程序中第 12 行中的 DataTable 類的 Rows 屬性的類型為 DataRowCollection 類。第 13 行中的 DataTable 類的 Select 方法返回 DataRow[] 數組。我們知道,foreach 語句對實現 System.Collections.IEnumerable 或 System.Collections.Generic.IEnumerable<T> 接口的數組或對象集合中的每個元素重復一組嵌入式語句。所以該 foreach 語句中的 row 變量的類型被推斷為 DataRow 類。這個程序的運行結果如下所示:
如果把上述程序中的第 13 行改為:
13: foreach (var row in dt.Rows)
這時,會出錯以下編譯錯誤:
這是因為 DataRowCollection 類只實現了 System.Collections.IEnumerable 接口,而沒有實現 System.Collections.Generic.IEnumerable<DataRow> 接口,所以該 foreach 語句中的 row 變量的類型被推斷為 System.Object 類。
僅實現 IEmnumerable 接口而沒有實現 IEnumerable<T> 接口的集合類還有非常多,例如:
因為泛型是在 .NET 2.0 中才引入的,上述類中的大部分都是在 .NET 1.0 中已經就有了。但是 Microsoft 應該在 .NET 2.0 以後為上述類實現 IEnumerable<T> 接口才對。這不能不說是 .NET Framework Base Class Library 的一個遺憾。請參閱 MSDN 論壇上的一個相關的帖子:Missing linq extension method 。
幸運的是,在 .NET Framework 3.5 及其以後的版本中, 在 System.Linq 命名空間中增加了 IEnumerable.Cast<TResult> 擴展方法,可以將 IEnumerable 的元素轉換為指定的 TResult 類型。這樣,上述程序第 13 行改為:
13: foreach (var row in dt.Rows.Cast<DataRow>())
就可以正常工作了。當然,在這個場合還有更好的解決方案,就是將第 13 行改為:
13: foreach (DataRow row in dt.Rows)
就可以了。
也有好消息,就是 System.Collections.ObjectModel 命名空間中的 Collection<T> 類實現了 IEnumerable<T> 接口,而 Collection<T> 類有很多派生類。例如 System.Net 命名空間中的 IPEndPointCollection 類就是從 Collection<IPEndPoint> 類繼承,因此也就實現了 IEnumerable<IPEndPoint> 接口。