【问题标题】:Get current index from foreach loop [duplicate]从foreach循环中获取当前索引[重复]
【发布时间】:2016-08-21 07:01: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                   

  }
}

如何做到这一点

【问题讨论】:

    标签: c# silverlight for-loop foreach


    【解决方案1】:

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

    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&lt;object&gt; 放在您的外部循环将其转换为IEnumerable&lt;object&gt;

    问题中您的数据类型不清楚,但我假设 object 因为它是项目源(可能是 DataGridRow)...您可能想检查它是否可以直接转换为通用 @987654337 @而不必打电话给Cast&lt;object&gt;(),但我不会做这样的假设。


    这一切都说了:

    “索引”的概念对于 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,索引也将毫无意义......在某些时候 - 当它溢出时 - 对于两个不同的值,索引将是相同的)。

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

    【讨论】:

    • 选项 3 非常棒。我喜欢它!
    • @pnizzle 这不是最优的,因为它循环列表两次...
    • @cvbattum 不,它没有......是什么让你认为它循环了两次? (编辑:我只是tested it,它绝对不会循环两次)
    【解决方案2】:
    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;
    }
    

    【讨论】:

    • 如果您可以使用for,我看不出使用foreach 的意义...:P
    【解决方案3】:

    使用Enumerable.Select<TSource, TResult> Method (IEnumerable<TSource>, Func<TSource, Int32, TResult>)

    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 ...
    }
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2011-06-02
        • 2015-05-03
        • 2010-11-29
        • 2013-07-18
        • 1970-01-01
        • 2014-07-13
        • 2011-03-26
        • 2021-06-04
        • 1970-01-01
        相关资源
        最近更新 更多