为AsEnumerable使用泛型而不是强制转换

本文关键字:转换 AsEnumerable 泛型 | 更新日期: 2023-09-27 18:22:44

我是C#中泛型的新手,在读一本书时偶然发现了一个例子:

var cars = from car in data.AsEnumerable()
  where
    car.Field<string>("Color") == "Red"
    select new
    {
      ID = car.Field<int>("CarID"),
      Make = car.Field<string>("Make")
    };

作者说,与(string)car["Color"]相比,car.Field<string>("Color")提供了额外的编译时间检查。但是编译器如何知道car.Field<string>("Color")可用于"Color"而不可用于"CarID"呢?或者我错过了另一种"额外的编译时检查"?

为AsEnumerable使用泛型而不是强制转换

它不会给您任何额外的编译时检查。如果使用了错误的类型,在这两种情况下,运行时都会出现异常。

但是,做一些简单的铸造所不能做的额外的事情是有用的。例如,Field<int>("CarId")可以调用将字段中的string转换为int的方法。

假设您谈论的是DataRow.Field<T>(),那么,根据文档,它主要用于正确处理null值和可为null的类型。

编译器不知道,您指定的字段"Color"是字符串类型。在内部,Field<T>()方法实现了这一点。

如果执行强制转换((string)car["Color"]),如果字段值无法转换为目标类型,则可能会遇到运行时异常。

在内存中,如果指定car.Field<string>("ColorID"),则可以安全地将int转换为字符串,而不会出现任何问题。

具体来说,car.Field<string>("Color")的真正好处是它封装了与DBNull.Value相等的测试字段值,使代码更干净、更易于阅读。

在您的示例中,如果"Color"字段的值为null,则Field<T>扩展方法将返回null,而car["Color"]将返回DBNull.Value。不能将DBNull.Value强制转换为string,因此表达式(string)car["Color"]在这种情况下会引发InvalidCastException

在开发DataSetExtensions类之前,您需要一个有点冗长的表达式来将该字段的值分配给string变量:

var color = DBNull.Value.Equals(car["Color"]) ? null : (string)car["Color"];

正如svick所指出的,Field<T>的另一个好处是,它使您能够使用相同的语法处理可为null的类型和引用类型。