Why can't I do foreach (var Item in DataTable.Rows)?
Rows
effectively returns IEnumerable
(DataRowCollection
), so the compiler can only pick object
as the type for var
. Use Rows.Cast<DataRow>
if you want to use var
.
Cast
is defined on Enumerable, so you have to include System.Linq.
Why can't C# infer the type of a DataTable Row
Why can't C# infer the type of row as it would if I was trying to iterate over a string[] for example?
TL;DR: DataTable
predates generics :(
DataTable.Rows
is declared to return DataRowCollection
, which derives from InternalDataCollectionBase
. That implements the non-generic ICollection
interface, which means that the compiler can't infer the type of row
beyond just object
.
This isn't specific to DataTable
- any time you have something that only implements IEnumerable
rather than IEnumerable<T>
(and doesn't have a more specific GetEnumerator
method for the compiler to use), the inferred iteration element type is just object
. When you specify an explicit type for the variable in the foreach
loop, the compiler silently inserts a cast for you.
I'd keep the change exactly as you've got it, but an alternative would be to use the Cast
LINQ method:
foreach (var row in currentTable.Rows.Cast<DataRow>())
{
var valueAtCurrentRow = row[0];
}
How to iterate through a DataTable
DataTable dt = new DataTable();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);
foreach(DataRow row in dt.Rows)
{
TextBox1.Text = row["ImagePath"].ToString();
}
...assumes the connection is open and the command is set up properly. I also didn't check the syntax, but it should give you the idea.
How to 'foreach' a column in a DataTable using C#?
This should work:
DataTable dtTable;
MySQLProcessor.DTTable(mysqlCommand, out dtTable);
// On all tables' rows
foreach (DataRow dtRow in dtTable.Rows)
{
// On all tables' columns
foreach(DataColumn dc in dtTable.Columns)
{
var field1 = dtRow[dc].ToString();
}
}
Use of C# var for implicit typing of System.Data.Datarow
That's because Rows
is DataRowCollection
, which in turn is IEnumerable
and not IEnumerable<DataRow>
, which means that type inferred will be object
.
When you explicitly state type in foreach
, you instruct c# to add cast to each call, which is why it works.
Why is my added datatable rows disappearing from the table as soon as my foreach loop closes?
NewRow()
doesn't add the row. You need to do that manually at the bottom of the loop via .Rows.Add(row)
. You should also probably create the NewRow()
per iteration.
foreach (var item in issuesByClass)
{
var row = summaryTable.NewRow();
// ...
summaryTable.Rows.Add(row);
}
Behavior of var
The property DataTable.Rows
uses an older style (non-generic) collection. The actual type is DataRowCollection
which defines an enumerator that is non-generic so it returns instances of type object
. To address this problem a new extension method was provided in later versions of the framework (3.5+) called DataTable.AsEnumerable
that returns a properly-typed enumerator:
DataTable test = new DataTable();
foreach (var r in test.AsEnumerable())
{
r[1].ToString();
}
If you are stuck on an older version of .NET you would have to cast r
to DataRow
manually.
Updating a row in a datatable during a foreach C#
as an alternative, using a traditional for loop over a foreach would mean not doing any data copying or anything and would likely run though the datatable faster
for(int i=0;i<table.Rows.Count;i++)
{
if (table.Rows[i]["seqlinnum"].ToString() == "0")
{
table.Rows[i]["seqlinnum"]=maxSequenceNumber; maxSequenceNumber++;
}
}
Object type not recognised on foreach loop
As is stated in the other answers, TreeNodeCollection
is a collection of object
objects. This is because WinForms was a part of the C# language from the beginning (.NET 1.1), and generics weren't added until .NET 2.0. For backwards compatibility reasons, they did not alter the class to also implement IEnumerable<TreeNode>
.
As you discovered, the only way to process them is by explicitly typing the objects as TreeNode
within your foreach
loop. That is because var
wasn't added until .NET 3.5.
One other alternative (though more verbose) would be to get the objects of the type that you want:
foreach (var child in nodes.OfType<TreeNode>())
As I said, this is more verbose, and you would be better suited to just explicitly cast the objects. However, the OfType
method is a good one to have in your repertoire.
Clarification
As mentioned in comments on Patrick's answer, another option is .Cast<T>()
. However, if you do that, exceptions are thrown if an item cannot be cast to the specified type. In a situation like this, you are fine because based on the way that the collection is created, you won't have anything that is not a TreeNode
. But, in other collections, it is possible to have other types based on super classes, etc. OfType<T>()
will ignore anything that is not of the type you are requesting.
Why does var evaluate to System.Object in foreach (var row in table.Rows)?
That's because the DataRowCollection class only implements the non-generic version of IEnumerable
. So the compiler doesn't know what the type of the variable is.
By explicitly putting the type in there, you basically tell the compiler to generate an explicit cast from object
to DataRow
.
This is a problem you'll find with many of the collections and classes added back in the .NET 1.x days, before generics were available.
Related Topics
How to Convert Datetime in Specific Timezone
How to Sort a List<T> by Multiple T.Attributes
How to Find the Position of a Cursor in a Text Box? C#
How to Catch Exceptions from a Threadpool.Queueuserworkitem
Serialization Breaks in .Net 4.5
"Padding Is Invalid and Cannot Be Removed" Using Aesmanaged
Exclude a Field/Property from the Database with Entity Framework 4 & Code-First
Displaying Tooltip on Mouse Hover of a Text
How to Draw a Rounded Rectangle in C#
Registry.Localmachine.Opensubkey() Returns Null
How to Have a Variable Number of Generic Parameters
Split String into Smaller Strings by Length Variable
Show Authentication Dialog in C# for Windows Vista/7
Process.Start to Open an Url, Getting an Exception
Wpf: Cannot Reuse Window After It Has Been Closed
Moq + Unit Testing - System.Reflection.Targetparametercountexception: Parameter Count Mismatch