Why isn't this cast working?
This code works:
foreach(DataColumn column in table.Columns)
{
// do whatever
}
But this code doesn't:
(IEnumerable<DataColumn>)(table.Columns)
The .Columns
property returns a开发者_如何转开发 DataColumnCollection which is an InternalDataCollectionBase, which implements IEnumerable, so it should work.
The error I get is
Cannot convert type 'System.Data.DataColumnCollection' to 'System.Collections.Generic.IEnumerable'
DataColumnCollection
implements IEnumerable
, and each returned row is a DataColumn
, but it doesn't implement IEnumerable<DataColumn>
. As it doesn't implement the interface, you can't cast to the interface. As the class is sealed, the compiler knows that the value can't possibly implement the interface, so you can't even cast to it at compile-time.
Use the LINQ Cast
method insted:
table.Columns.Cast<DataColumn>()
That's effectively an adapter method - each element in the column collection will be lazily cast to DataColumn
as you fetch it from the result.
The reason the foreach
compiles is that the compiler adds an explicit cast for you. For instance, this will compile:
foreach (string x in table.Columns)
{
}
... but it'll throw an exception at execution time.
It's because DataColumnCollection implements IEnumerable
, but not IEnumerable<T>
.
var columns = (IEnumerable)(table.Columns)
should work
IEnumerable and IEnumerable aren't related in any way. (however IEnumerable<DataColumn>
inherits from IEnumerable<object>
which could be duck typed to IEnumerable using dynamic, but it doesn't really help you (even if it's a lot of fun) )
In the first case you are individually casing each time within the Columns collection, but in the second you are casting the entire collection at once. It's really no different than:
// Cats implements IAnimal
Cats[] cats = new Cats[20];
...
IAnimal animal = cats[0];
versus
// this you cannot do
Cats[] cats = new Cats[20];
IAnimal[] animal = cats;
However, it is moot, as you can do this:
table.Columns.Cast<DataColumn>()
And be done with it. Notice that using the Cast<>
is preferable to simply getting a generic IEnumerable as the strong typing is preserved.
This is because DataColumnCollection only implements IEnumerable
, so you cannot cast it to the generic version IEnumerable<DataColumn>
. When using foreach
, the compiler does the casting for you on each element by convention.
Try this:
var columns = table.Columns as IEnumerable;
精彩评论