我们来看看以下程序吧:
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> 接口的集合类还有非常多,例如:
- System.Data.DataColumnCollection
- System.Data.ConstraintCollection
- System.Data.Common.DataTableMappingCollection
- System.Windows.Forms.DataGridViewRowCollection
- System.Web.UI.WebControls.GridViewRowCollection
因为泛型是在 .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> 接口。
参考资料
- Missing linq extension method
- MSDN: foreach, in (C# Reference)
- MSDN: DataRowCollection 类(System.Data)
- MSDN: IPEndPointCollection 类(System.Net)
- MSDN: Collection(T) 类(System.Collections.ObjectModel)
- MSDN: IEnumerable 接口(System.Collections)
- MSDN: IEnumerable(T) 接口(System.Collections.Generic)
- MSDN: Enumerable.Cast(TResult) 方法(System.Linq)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
2007-08-22 使用 C# 开发智能手机软件:推箱子(七)