为什么这个演员不工作?

时间:2011-08-08 18:52:44

标签: c# collections

此代码有效:

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

但是这段代码没有:

(IEnumerable<DataColumn>)(table.Columns)

.Columns属性返回一个DataColumnCollection InternalDataCollectionBase,它实现了IEnumerable,因此它应该可以工作。

我得到的错误是

  

无法将类型'System.Data.DataColumnCollection'转换为'System.Collections.Generic.IEnumerable'

5 个答案:

答案 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;