从 foreach 循环中获取当前索引

本文关键字:取当前索引 循环 foreach | 更新日期: 2024-12-05 18:26:08

使用 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                   
  }
}

如何实现这一点

从 foreach 循环中获取当前索引

你不能

,因为IEnumerable根本没有索引...如果确定枚举的元素少于 int.MaxValue(如果使用 long 索引,则long.MaxValue),则可以:

  1. 不要使用 foreach,并使用 for 循环,首先将IEnumerable转换为泛型可枚举:

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

    int i = 0;
    foreach(var row in list)
    {
       /* .... */
       ++i;
    }
    
  3. 通过 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>

你的数据类型从这个问题中不清楚,但我假设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())
{
  /* ... */
}

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

因此,虽然给出的示例适用于典型用法,但如果可以避免索引,我宁愿根本不使用索引。

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;
}
use enumerable.Select<TSource,> Method (IEnumerable

Func<TSource,>)

list = list.Cast<object>().Select( (v, i) => new {Value= v, Index = i});
foreach(var row in list)
{
    bool IsChecked = (bool)((CheckBox)DataGridDetail.Columns[0].GetCellContent(row.Value)).IsChecked;
    row.Index ...
}

您在这里有两个选择,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
}