【问题标题】:C# newbie: find out the index in a foreach blockC#新手:找出foreach块中的索引
【发布时间】:2009-07-28 07:39:52
【问题描述】:

我有一个 foreach 块,我想在其中绘制 foreach 内的步骤索引以进行跟踪调试。作为一个 C# 新手,我这样做如下:

int i = 1;

foreach (x in y)
{
    ... do something ...
    WriteDebug("Step: "+i.ToString());
    i++;
}

我想知道是否有任何方法可以获取当前步骤索引的值,而无需为此目的显式创建变量。

编辑:澄清一下,我显然很熟悉 for 循环的选项,但它不是我正在经历的数组,而是一个无序的集合。编号的原因只是为了显示调试级别的进度,没有其他目的。

【问题讨论】:

  • 集合上是否没有 Count 或 Length 属性?你在循环一个基本的枚举器吗?
  • @Binary Warrior:在考虑 for 循环时,困扰我的不是计数或长​​度,而是索引随机访问。我正在使用由 COM 对象公开的集合,该对象的“记录”访问方法正在使用 foreach 迭代器。它也是非常干净的代码。所以我想保留foreach,我更喜欢保留显式变量定义,而不是用for循环替换foreach,我需要去搜索索引随机访问方法(并且在我看来让我的代码不那么干净) .

标签: c# foreach


【解决方案1】:

与其他一些答案相反,我很乐意将 foreach 与计数器混合使用(根据问题中的代码)。这保留了您使用 IEnumerable[<T>] 的能力,而不需要索引器。

但如果你愿意,在 LINQ 中:

    foreach (var pair in y.Select((x,i) => new {Index = i,Value=x})) {
        Console.WriteLine(pair.Index + ": " + pair.Value);
    }

(问题中的计数器方法更简单,更有效,但上面应该更好地映射到 Parallel.ForEach 等一些场景)。

【讨论】:

  • 马克,你上面的选择语句让我头疼:)(我不是 linq 专家)。增加 i 的魔法在哪里?
  • Inside Select ;-p 基本上,你需要给 Select a Func<TInput,int,TOutput> 这个重载 - 即给定值和索引,做一些事情......见 MSDN:msdn.microsoft.com/en-us/library/bb534869.aspx
【解决方案2】:

不,没有。

这是一个最好使用基本 for 循环的实例

for(int i = 0; i < y.Count; i++)
{
}

而不是一个for每个循环

编辑:回应提问者的澄清。

如果您正在迭代一个没有大小属性​​(例如长度或计数)的枚举器,那么您的方法将尽可能清晰。

二次编辑
鉴于我的德鲁特人,这些天我会使用选择来接受 Marc 的回答。

【讨论】:

  • 请参阅我的说明。 for 循环对我不起作用。对我来说,使用 foreach 比正确绘制数字更重要......谢谢
  • 感谢您的开明回答:)
【解决方案3】:

不,在 foreach 循环中确实没有隐含的“计数器”。

foreach 循环在幕后所做的是创建一个 IEnumerator,然后逐个遍历项目,调用 IEnumerator 接口上的 .MoveNext() 方法。

(很遗憾?)IEnumerator 接口上没有公开计数器变量 - 只有 .Reset() 和 .MoveNext() 方法和 Current 属性(返回当前项)

马克

【讨论】:

  • 如果他需要并且想要保留 foreach,那么是的,拥有一个单独的 int 变量作为索引是唯一且正确的做法,不是吗?
  • Macr,很抱歉,但在我看到提问者更新他们的问题之前,我看到了你的回答。我已经删除了我不必要的讽刺评论。一千次道歉。
  • 好吧,不费吹灰之力,Binary Warrier!
【解决方案4】:

您的方法非常清晰。但是,您可能需要注意 i++ 部分实际上与循环的核心功能无关(不涉及计数/长度/其他参数)。因此,您可能需要考虑将 both writeDebug 和 i++ 移动到单独的方法/类 (updateProgress()) 中,然后简单地从循环中调用它。

【讨论】:

  • 这样做的缺点是您必须使用ref int i,但好处是您可以将第二种方法标记为[Conditional("DEBUG")],这样它就不会包含在发布版本中...
【解决方案5】:

foreach 使用 IEnumerator 接口,该接口具有 Current 属性以及 MoveNext 和 Reset 方法。

Current 返回 Enumerator 当前所在的对象,MoveNext 将 Current 更新为下一个对象。

foreach 中没有索引的概念,我们无法确定枚举的顺序。

您必须为此应用一个变量,或者使用 for 循环来代替。

我更喜欢使用 for lop 而不是使用变量来跟踪它。

【讨论】:

    【解决方案6】:

    不,没有办法在 foreach 循环中得到它。对于这种情况,您应该使用 for 循环,或者如您所述,显式创建一个用于计数的变量。

    【讨论】:

      【解决方案7】:

      这取决于您要循环的枚举器的实际类型。但是,很多集合都有IndexOf方法

              ArrayList arrayList = new ArrayList();
      
              arrayList.Add("A");
              arrayList.Add("B");
              arrayList.Add("C");
      
              foreach (string item in arrayList)
              {
                  int i = arrayList.IndexOf(item);
              }
      

      当然,如果您的列表中有重复的项目,这将不起作用。这也不是最有效的解决方案。我会坚持你原来的,只保留一个变量来跟踪索引。

      【讨论】:

      • 我对 foreach 中“步骤”的顺序感兴趣。 “IndexOf”是否一定会返回与 foreach 相同的顺序? (即使值是唯一的)
      • 我不知道。如果你有 IndexOf 方法,你将不得不在你的 COM 对象上尝试这个。但是,在查看您的其他 cmets 时,我想我仍然会坚持使用您的原始代码。
      【解决方案8】:

      我不知道你的例子中的“y”到底是什么,但也许你可以这样写:

        foreach (var x in y.WithIndex())
        {
          WriteDebug(String.Format("Step: {0}", x.Index));
        }
      

      前提是您将以下扩展类添加到您的项目中:

        public static class Extensions
        {
          public static IEnumerable<IndexValuePair<T>> WithIndex<T>(this IEnumerable<T> source)
          {
            if (source == null) throw new ArgumentNullException("source");
            var position = 0;
            foreach (T value in source)
            {
              yield return new IndexValuePair<T>(position++, value);
            }
          }
        }
      
        public class IndexValuePair<T>
        {
          public IndexValuePair(Int32 index, T value)
          {
            this.index = index;
            this.value = value;
          }
      
          private readonly Int32 index;
          public Int32 Index
          {
            get { return index; }
          }
      
          private readonly T value;
          public T Value
          {
            get { return value; }
          }
        }
      

      HTH, 德让

      【讨论】:

        【解决方案9】:

        如果您绝对需要索引,请改用传统的 for 循环。

        for (int i = 0; i < y.Count; i++)
        {
            WriteDebug("Step: "+i.ToString());    
        }
        

        【讨论】:

          【解决方案10】:

          试试这个:

          foreach (var x in y)
          {
              //... do something ...
              WriteDebug("Step: "Array.IndexOf(y,x).ToString());
          
          }
          

          【讨论】:

            猜你喜欢
            • 2017-02-04
            • 1970-01-01
            • 1970-01-01
            • 2010-09-13
            • 2016-08-22
            • 2013-03-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多