从foreach循环中获取当前索引

15

使用 C# 和 Silverlight

如何获取列表中当前项目的索引?

代码:

IEnumerable list = DataGridDetail.ItemsSource as IEnumerable;
List<string> lstFile = new List<string>();


foreach (var row in list)
{
  bool IsChecked = (bool)((CheckBox)DataGridDetail.Columns[0].GetCellContent(row)).IsChecked;
  if (IsChecked)
  {

    // Here I want to get the index or current row from the list                   

  }
}

如何实现这一目标

4个回答

28

由于 IEnumerable 没有索引,所以您无法这样做……如果您确定您的可枚举对象中的元素数量小于int.MaxValue(或者使用long索引,则小于long.MaxValue,您可以:

  1. 不要使用 foreach 循环,而是使用 for 循环,并先将您的 IEnumerable 转换为通用可枚举对象:

  2. var genericList = list.Cast<object>();
    for(int i = 0; i < genericList.Count(); ++i)
    {
       var row = genericList.ElementAt(i);
       /* .... */
    }
    
  3. 具有外部索引:

    int i = 0;
    foreach(var row in list)
    {
       /* .... */
       ++i;
    }
    
  4. 通过 Linq 获取索引:

    foreach(var rowObject in list.Cast<object>().Select((r, i) => new {Row=r, Index=i}))
    {
      var row = rowObject.Row;
      var i = rowObject.Index;
      /* .... */    
    }
    

对于您的情况,由于您的 IEnumerable 不是泛型的,我建议使用带外部索引的 foreach(第二种方法)……否则,你可能想在循环之外使用 Cast<object> 将其转换为 IEnumerable<object>

根据问题中没有明确说明数据类型,但我认为它是一个项源(可能是 DataGridRow),你可以检查是否可以直接将其转换为泛型的 IEnumerable<object> 而不需要调用 Cast<object>(),但我不会做出这样的假设。


总之:

“索引”的概念对于 IEnumerable 来说是陌生的。一个 IEnumerable 可能是无限的。在您的示例中,您正在使用 DataGridItemsSource,因此您的 IEnumerable 更可能只是一组对象(或 DataRows),具有有限的(并且希望小于 int.MaxValue)成员数量,但 IEnumerable 可以表示任何可枚举的东西(而枚举可能永远不会结束)。

以下是一个例子:

public static IEnumerable InfiniteEnumerable()
{
  var rnd = new Random();
  while(true)
  {
    yield return rnd.Next();
  }
}

如果你这样做:

foreach(var row in InfiniteEnumerable())
{
  /* ... */
}

如果您使用 int(或 long)索引,您的foreach循环将是无限的:最终会溢出(除非您使用了一个 unchecked 上下文,否则如果您不断添加,它会抛出异常:即使您使用了 unchecked,索引也会变得毫无意义...在某个时候 - 溢出时 - 索引将对于两个不同的值相同)。

因此,虽然给出的示例对于典型用法有效,但如果可能的话,我宁愿根本不使用索引。


选项3太棒了。我喜欢它! - pnizzle
@pnizzle 这并不是最优的解决方案,因为它需要两次循环列表... - cvbattum
@cvbattum 不,它不会...是什么让你认为它会循环两次?(编辑:我刚刚测试过了,它绝对不会循环两次) - Jcl

9
IEnumerable list = DataGridDetail.ItemsSource as IEnumerable;
List<string> lstFile = new List<string>();

int i = 0;
foreach (var row in list)
{
bool IsChecked = (bool)((CheckBox)DataGridDetail.Columns[0].GetCellContent(row)).IsChecked;
if (IsChecked)
{
  MessageBox.show(i);
--Here i want to get the index or current row from the list                   

}
 ++i;
}

5
如果你可以使用 for,我就看不出使用 foreach 的意义了... :P - Matías Fidemraizer

1

0
你有两个选择,1. 使用 for 而不是 foreach 进行迭代。但在你的情况下,集合是 IEnumerable 类型,且集合的上限未知,因此 foreach 是最好的选择。所以我建议使用另一个整数变量来保存迭代计数:以下是代码示例:

int i = 0; // for index
foreach (var row in list)
{
    bool IsChecked;// assign value to this variable
    if (IsChecked)
    {    
       // use i value here                
    }
    i++; // will increment i in each iteration
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接