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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With