此代码有效:
foreach(DataColumn column in table.Columns)
{
// do whatever
}
但是这段代码没有:
(IEnumerable<DataColumn>)(table.Columns)
.Columns
属性返回一个DataColumnCollection InternalDataCollectionBase,它实现了IEnumerable,因此它应该可以工作。
我得到的错误是
无法将类型'System.Data.DataColumnCollection'转换为'System.Collections.Generic.IEnumerable'
答案 0 :(得分:19)
DataColumnCollection
实现了IEnumerable
,每个返回的行 一个DataColumn
,但它没有实现IEnumerable<DataColumn>
。由于它没有实现接口,因此无法转换为接口。由于类是密封的,编译器知道该值不可能实现接口,因此您甚至无法在编译时转换它。
使用LINQ Cast
方法:
table.Columns.Cast<DataColumn>()
这实际上是一个适配器方法 - 当你从结果中获取时,列集合中的每个元素都会被懒惰地转换为DataColumn
。
foreach
编译的原因是编译器为您添加了一个显式的强制转换。例如,这将编译:
foreach (string x in table.Columns)
{
}
...但它会在执行时抛出异常。
答案 1 :(得分:3)
这是因为DataColumnCollection实现了IEnumerable
,而不是IEnumerable<T>
。
var columns = (IEnumerable)(table.Columns)
应该有效
IEnumerable和IEnumerable以任何方式无关。 (但是IEnumerable<DataColumn>
继承自IEnumerable<object>
,可以使用动态将其类型化为IEnumerable,但它并没有真正帮助你(即使它很有趣))
答案 2 :(得分: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更好,因为保留了强类型。
答案 3 :(得分:0)
这是因为DataColumnCollection仅实现IEnumerable
,因此您无法将其强制转换为通用版本IEnumerable<DataColumn>
。使用foreach
时,编译器按惯例为每个元素执行转换。
答案 4 :(得分:0)
试试这个:
var columns = table.Columns as IEnumerable;