为什么这个转换没有起作用?

7

这段代码能正常工作:

foreach(DataColumn column in table.Columns)
{
    // do whatever
}

但是这段代码不行:
(IEnumerable<DataColumn>)(table.Columns)
.Columns属性返回一个DataColumnCollection,它是实现了IEnumerable接口的InternalDataCollectionBase类型,因此应该可以使用。但我收到的错误是:“无法将类型'System.Data.DataColumnCollection'转换为'System.Collections.Generic.IEnumerable'”。
5个回答

19

DataColumnCollection 实现了 IEnumerable 接口,每个返回的行都是一个 DataColumn,但它不实现 IEnumerable<DataColumn>。因为它没有实现这个接口,所以你无法将其强制转换为该接口。由于该类是密封的,编译器知道该值不可能实现该接口,因此甚至在编译时也无法将其强制转换。

使用 LINQ 的 Cast 方法代替:

table.Columns.Cast<DataColumn>()

这实际上是一个适配器方法 - 每个列集合中的元素在从结果获取时将被惰性地转换为 DataColumn

foreach 可以编译的原因是编译器会为您添加显式转换。例如,下面的代码将会编译

foreach (string x in table.Columns)
{
}

... 但它将在执行时抛出异常。


3

这是因为DataColumnCollection实现了IEnumerable,但没有实现IEnumerable<T>。

var columns = (IEnumerable)(table.Columns)应该可以工作。

IEnumerable和IEnumerable<T>没有任何关系。(然而,IEnumerable<DataColumn>继承自IEnumerable<object>,可以使用dynamic进行duck类型转换到IEnumerable,但它并不能真正帮助你(即使它非常有趣))


我认为你的意思是"[...]但不包括IEnumerable<DataColumn>[...]"。 - Tipx

1

在第一种情况下,您正在单独对Columns集合中的每个时间进行大小写转换,但在第二种情况下,您一次性转换整个集合。这与以下代码没有什么区别:

// Cats implements IAnimal
Cats[] cats = new Cats[20]; 
...
IAnimal animal = cats[0];

对比

// this you cannot do
Cats[] cats = new Cats[20]; 
IAnimal[] animal = cats;

然而,这已经没有意义了,因为你可以这样做:

table.Columns.Cast<DataColumn>()

搞定它。请注意,使用Cast<>比仅获取通用IEnumerable更可取,因为强类型保留。


0

试试这个:

var columns = table.Columns as IEnumerable;

0
这是因为 DataColumnCollection 只实现了 IEnumerable 接口,所以你不能将它强制转换为泛型版本的 IEnumerable。当使用 foreach 时,编译器会按照惯例为每个元素执行强制转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接