6

Possible Duplicate:
Why does var evaluate to System.Object in “foreach (var row in table.Rows)”?

I was rather suprised to discovered the following today....

SqlDataReader reader = cmd.ExecuteReader();
DataTable schemaTable = reader.GetSchemaTable();


// the following compiles correctly
foreach (DataRow field in schemaTable.Rows)
{
    Console.WriteLine(field["ColumnName"]);
}


// the following does not compile as 'var' is of type 'object'
foreach (var field in schemaTable.Rows)
{
    // Error: Cannot apply indexing with [] to an expression of type 'object'
    Console.WriteLine(field["ColumnName"]);
}

Whats going on here?

Is this a type inference failure? And if so, what causes it?

Or is it part of the defined behaviour or var? And if so, why?

I thought the idea of var was that you could use it anywhere in a variable declaration/initialisation without changing behaviour.

Community
  • 1
  • 1
fearofawhackplanet
  • 52,166
  • 53
  • 160
  • 253
  • 1
    `DataRowCollection.GetEnumerator()` returns `IEnumerator`. The type of `IEnumerator.Current` is `object`. – Jaroslav Jandek Feb 08 '11 at 13:47
  • [exact duplicate question](http://stackoverflow.com/questions/2325777/why-cant-i-do-foreach-var-item-in-datatable-rows) Basically Rows is a `DataRowCollection`, so the compiler picks up `Object`, not `DataRow` – Axarydax Feb 08 '11 at 13:42

3 Answers3

4

The point here is not var, but the foreach loop. The foreach loop can optionally cast the iterator in addition to iterating itself.

So you can do the following:

List<object> test = new List<object>();
test.Add(1);
test.Add(2);
test.Add(3);
foreach( int i in test ){
  i.Dump();
}

So even if the list is of type object, it can be casted to int on the fly inside the foreach.

Øyvind Bråthen
  • 59,338
  • 27
  • 124
  • 151
  • I did not know this, thanks. I was wondering why the iterator didn't require an explicit cast in the first example. – fearofawhackplanet Feb 08 '11 at 13:49
  • Please note that if you do this, you will get a null reference exception if the type to the left of the variable name does not match the actual type of the object in the enumeration. You can't use it to go `foreach(DerivedType derived in ListOfBaseTypes)` and expect it to work properly unless everything in your `ListOfBaseTypes` is of type `DerivedType` – Stephen May 12 '14 at 04:24
1

DataTable.Rows returns System.Data.DataRowCollection which is a subclass of InternalDataCollectionBase.

The GetEnumerator memthod on this returns IEnumerator, rather than IEnumerator<DataRows>.

Hence the only type information available is that it returns object, so when you specify you are enumerating DataRow you are adding your own cast, which var does not.

Nick Jones
  • 6,413
  • 2
  • 18
  • 18
0

The confusion is that foreach(SomeType thing in SomeCollection) doesn't just iterate through the collection, it also attempts a cast to SomeType for each item as it iterates. But with var there's nothing to cast to.

Massif
  • 4,327
  • 23
  • 25