【问题标题】:For each with a dynamic list?对于每个都有一个动态列表?
【发布时间】:2011-09-01 23:33:28
【问题描述】:

我有一个遍历数据库的 for each 循环来检查已标记为转换的文件。目前我有以下代码:

            /* All files flagged for invidual conversion will be stored in here. */
            ArrayList files = vc.getFilesForInvidualConversion();
            foreach (FileInfoExtended file in files)
            {
                // As long as the status flag hasn't been changed it can continue.
                if (abort == false)
                {
                    if (vc.isFileInUse(file) == false)
                    {
                            // Converting the video file.
                            vc.convertVideoToFLV(file);
                    }
                }
                vc.getFilesForInvidualConversion();
            }

在第一行中,您可以看到我用对象填充了一个 ArrayList,它将为每个对象运行一个对象。但是,在列表中的每个文件之后,我想检查可能需要转换的新文件。当我再次填充 ArrayList 时,for each 似乎没有注意到,它继续使用从第一行代码收到的原始文件。我更希望它更新“文件”-ArrayList,以便它也可以转换新文件。

这可能吗?

编辑:你为这个场景提供的所有工作,但我想添加一些东西。是否可以在循环期间从列表中删除文件?并使它不会转换那个?

编辑 2:这是我现在拥有的:

            List<FileInfoExtended> files = vc.getFilesForInvidualConversion();
            while (files.Count > 0)
            {
                if (abort == false)
                {
                    if (vc.isFileInUse(files[0]))
                    {
                        vc.convertVideoToFLV(files[0]);
                    }
                }
                files = vc.getFilesForInvidualConversion();
            }

它适用于两种情况(将文件添加到列表中以及从列表中删除文件时)。我不知道它是否在性能方面是一个好的解决方案,但现在它适合我的需求。除非我忽略了一些问题?

任何评论将不胜感激! 亲切的问候, 弗洛里斯

【问题讨论】:

  • 尝试使用 for 而不是 foreach。 foreach 依赖于集合在其生命周期内不会发生变化。
  • 我不知道,这清除了很多东西!谢谢你的信息。

标签: c# dynamic foreach arraylist


【解决方案1】:

我建议使用其他集合而不是 ArrayList。例如Stack&lt;T&gt;。然后像这样写:

while (stack.Any())
{
    var item = stack.Pop();
    // convert item
}

// All items were converted

您可以随时stack.Push() 新项目。

P.S.:使用非泛型 ArrayList 有什么意义吗?

【讨论】:

  • 在写 ArrayList 的时候,我使用了另一种存储在 ArrayList 中的对象,实际上我只是忘记更正了,谢谢你的提醒。至于你的答案,我会研究所有这些并使用最适合我的一个。
  • 如果它反过来也能满足我的需求,但事实并非如此。检查我的原始帖子编辑以了解我的意思。
【解决方案2】:

您可以使用标准的“for”循环。 foreach 循环要求集合在遍历期间是不可变的。 'for' 循环没有这个约束。但是,在这种情况下,获取“for”循环的结束条件约束可能会很困难。

我会考虑保留一份已处理文件的列表,这样当你第二次通过时,你可以检查一下你是否已经处理了一个特定的文件。

【讨论】:

  • 我不知道 'for each' 循环可以与不可变集合一起使用,这可以解决很多问题!感谢您的信息。我认为你的回答和 Paul Keisters 会帮助我。
【解决方案3】:

执行此操作的明智方法是处理批次:当每个批次完成后,再获取另一个批次,直到遇到空批次(这与 @j0rd4n 建议的方法相同)。以下是如何将这个逻辑包装在一个漂亮的foreach 循环中:首先,创建类来管理迭代:

namespace StackOverflow6128549
{
    class FileInfoExtended
    {
        public int PropertyX { get; set; }
    }

    class IncrediblySmartIteration : IEnumerable<FileInfoExtended>
    {
        private List<FileInfoExtended> GetFilesToProcess()
        {
            throw new NotImplementedException();
        }

        #region IEnumerable<FileInfoExtended> Members

        private IEnumerator<FileInfoExtended> InternalGetEnumerator()
        {
            List<FileInfoExtended> filesToProcess = null;

            do
            {
                filesToProcess = GetFilesToProcess();

                foreach (var fi in filesToProcess)
                {
                    yield return fi;
                }
            }
            while (filesToProcess.Count > 0);
        }

        public IEnumerator<FileInfoExtended> GetEnumerator()
        {
            return InternalGetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return InternalGetEnumerator();
        }

        #endregion
    }
}

然后,您将能够使用简单的foreach 遍历这种类型的对象:

        var container = new IncrediblySmartIteration();

        foreach (var fi in container)
        {
            Console.WriteLine(fi.PropertyX);
        }

请注意,在设计 GetFilesToProcess() 方法时,您应该注意保证终止。请务必考虑在查找新文件时出错时会发生什么。

【讨论】:

  • 你的方法很适合我的要求,谢谢。但我注意到它不能反过来工作。例如,当文件已被另一个服务转换时。然后我需要从列表中删除该文件。但是如果我用这种方法测试它仍然会被转换。
【解决方案4】:

您可以使用递归将索引传递给递归函数,以便评估您在数组中的位置。

void ConvertRecursively(int index, typeForVC vc)
{
   if(abort)
      return;

   ArrayList files = vc.getFilesForInvidualConversion();
   if(index !< files.Count)
       return;

   else 
   {
      if (vc.isFileInUse(files[index]) == false)
       {
           // Converting the video file.
           vc.convertVideoToFLV(files[index]);
       }

       return ConvertRecursive(++index, vc);
   }
}

打电话就做:

ConvertRecursively(0, typeForVC vc);

更新:如果您还需要处理数组大小减小的情况,那么最后一个流控制语句是不必要的,所以我把它拿出来了:

void ConvertRecursively(int index, int prevSize, typeForVC vc)
{
   if(abort)
      return;

   ArrayList files = vc.getFilesForInvidualConversion();
   int sizeDifferential = files.Count <= prevSize ? prevSize - files.Count : 0;

   int adjustedIndex = index - sizeDifferential;

   if(adjustedIndex !< files.Count)
       return;

      if (vc.isFileInUse(files[adjustedIndex]) == false)
       {
           // Converting the video file.
           vc.convertVideoToFLV(files[adjustedIndex]);
       }

       return ConvertRecursive(++adjustedIndex, files.Count, vc);     
}

打电话就做:

ConvertRecursively(0, 0, typeForVC vc);

好的,所以现在我只是玩得开心。希望它对你有用。我还没有测试过这个 b.t.w.

【讨论】:

  • 它仅在您将文件添加到列表时有效,而不是在您删除文件时。
  • 可以调整,这只是一个起点。从列表中删除的项目在哪里?它应该可以工作,除非它从列表中的索引
  • @Floris,在这个(我更新的)场景中,只要文件尚未转换并且从列表中删除,你应该没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多