20

我是 C# 新手,对“var”的使用有疑问

当我使用以下代码时,一切都很好

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

但是当我更改为时DataGridViewRowvar我得到并错误指出

“object”不包含“Cells”的定义,并且找不到接受“object”类型的第一个参数的扩展方法“Cells”(您是否缺少 using 指令或程序集引用?)

4

4 回答 4

28

myGrid.Rows是类型DataGridViewRowCollection

这东西很老了,它的定义是:

public class DataGridViewRowCollection : ICollection, IEnumerable, IList

你看到非通用接口了吗?这个类可以实现IList<DataGridViewRow>,然后var就可以工作,但它是遗留的。

IEnumerable不传达有关项目类型的信息,并且该GetEnumerator函数在这里没有帮助,因为它返回一个IEnumerator,而它可以返回一个IEnumerator<DataGridViewRow>

本质上,C# 编译器寻找一个GetEnumerator函数,该函数返回一个对象,该对象具有MoveNext函数和Current属性(显式实现时的IEnumerable<T>/IEnumerable接口)。这种鸭子类型的方法是出于历史原因,它在泛型被引入语言之前就已经存在。循环变量将foreachCurrent属性的类型相同。并且在IEnumerator(非泛型变体)内,Currentobject.

明确指定类型:

foreach (DataGridViewRow row in myGrid.Rows)

只是将返回值转换Current为 a DataGridViewRow,因为缺乏更好的机制。

如果您真的想在这里使用该var关键字,您也可以使用 LINQ 来实现相同的效果:

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

这是可行的,因为扩展方法返回一个,而后者又使用,并最终成为枚举数属性的类型,因此传播了类型信息。Enumerable.Cast<T> IEnumerable<T>IEnumerator<T>TCurrent

我怀疑此时您是否会从这些细节中受益,但是当您了解有关该语言的更多信息时,您可能希望保留此信息以供进一步参考。您必须了解扩展方法和泛型类型才能掌握这一点。

于 2015-04-15T19:49:10.567 回答
13

这是因为该GridView.Rows属性返回一个GridViewRowCollection类型。

在这种情况下var,无法从使用中推断出该对象将是一个DataGridViewRow内部。

来源:GridView.Rows 属性

于 2015-04-15T19:48:49.833 回答
5

DataGridViewRow.RowsDataGridViewRowCollection类型,它不实现IEnumerable<DataGridViewRow>,只有IEnumerable。并且object是当您不指定强制转换为时编译器可以推断出的最佳DataGridViewRow猜测row

于 2015-04-15T19:48:42.947 回答
1

如果将 DataGridViewRow 更改为 Var C# 不确定是否有一个称为单元格的数组。要解决此问题,您可以将 var 强制转换为 DataGridViewRow,但是如果您知道该类型,则使用该类型几乎总是更好,请在线查找类型安全以获取更多信息。

于 2015-04-15T19:59:51.557 回答