简体   繁体   中英

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?)

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.

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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM