Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

var won't work with DataGridViewRow

I new to C# and have a question regarding the use of "var"

When I use the following code everything works great

foreach(DataGridViewRow row in myGrid.Rows)
{
    if (row.Cells[2].Value.ToString().Contains("51000"))
    {
        row.Cells[0].Value = "X";
    }
}

But when I change DataGridViewRow to var I get and error that states

'object' does not contain definition for 'Cells' and no extension method 'Cells' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

like image 617
Joaquin Avatar asked Apr 15 '15 19:04

Joaquin


4 Answers

myGrid.Rows is of type DataGridViewRowCollection.

This thing is pretty old, its definition reads:

public class DataGridViewRowCollection : ICollection, IEnumerable, IList

Do you see the non-generic interfaces? This class could implement IList<DataGridViewRow> and then var would just work, but it's legacy.

IEnumerable conveys no information about the item type, and the GetEnumerator function doesn't help here, because it returns an IEnumerator, while it could return an IEnumerator<DataGridViewRow>.

Essentially, the C# compiler looks for a GetEnumerator function which returns an object which has a MoveNext function and a Current property (or an IEnumerable<T>/IEnumerable interface when implemented explicitly). This duck-typing approach is for historical reasons, it existed before generics were introduced into the language. The foreach loop variable will be of the same type than the Current property. And within IEnumerator (the non-generic variant), Current is of type object.

Specifying the type explicitly:

foreach (DataGridViewRow row in myGrid.Rows)

simply casts the return value of Current to a DataGridViewRow, for lack of a better mechanism.

You could also use LINQ to achieve the same effect, if you really want to use that var keyword here:

foreach (var row in myGrid.Rows.Cast<DataGridViewRow>())

This works, because the Enumerable.Cast<T> extension method returns an IEnumerable<T>, which in turn makes use of IEnumerator<T>, and T ends up as the type of the Current property of the enumerator, so the type information is propagated.

I doubt you'll benefit from these details at this point, but you may want to keep this for further reference when you'll learn more about the language. You'd have to learn about extension methods and generic types to grasp this.

like image 171
Lucas Trzesniewski Avatar answered Nov 09 '22 11:11

Lucas Trzesniewski


It's because the GridView.Rows property returns a GridViewRowCollection type.

In this case var can't infer from usage that the object will be a DataGridViewRow inside.

Source: GridView.Rows Property

like image 41
Vitor Canova Avatar answered Nov 09 '22 09:11

Vitor Canova


DataGridViewRow.Rows is of type DataGridViewRowCollection, which doesn't implement IEnumerable<DataGridViewRow>, only IEnumerable. And object is the best guess which compiler can infer when you don't specify cast to DataGridViewRow for row

like image 5
ASh Avatar answered Nov 09 '22 10:11

ASh


If you change the DataGridViewRow to Var C# is unsure that there is an array called cells. To fix this you could cast the var as a DataGridViewRow however it is almost always better to use the type if you know it, look online for type safety to get more information.

like image 1
LiverpoolOwen Avatar answered Nov 09 '22 11:11

LiverpoolOwen