Текущий индекс цикла foreach - PullRequest
       10

Текущий индекс цикла foreach

1 голос
/ 02 января 2011

Есть ли способ узнать текущий прогон foreach без необходимости:

Int32 i;
foreach
   i++;

или это лучший вариант, который я получил?Кроме того, как я могу узнать максимальное количество элементов в этом цикле?То, что я пытаюсь сделать, это обновить индикатор выполнения во время цикла foreach в моей форме.

Это то, что у меня есть до сих пор:

    FileInfo[] directoryFiles = (new DirectoryInfo(folderBrowserDialog.SelectedPath)).GetFiles("*.*");
    foreach (FileInfo file in directoryFiles)
    {
        if ((file.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden || (file.Attributes & FileAttributes.System) == FileAttributes.System)
            continue;

        backgroundWorkerLoadDir.ReportProgress(i, file.Name);
        System.Threading.Thread.Sleep(10);
    }

Так что это должно быть примерно так, верно?

   for (Int32 i = 0; i < DirectoryFiles.Length; i++)
   {
       if ((DirectoryFiles[i].Attributes & FileAttributes.Hidden) == FileAttributes.Hidden || (DirectoryFiles[i].Attributes & FileAttributes.System) == FileAttributes.System)
           continue;

       backgroundWorkerLoadDir.ReportProgress((i / DirectoryFiles.Length) * 100, DirectoryFiles[i].Name);
       System.Threading.Thread.Sleep(10);
   }

Ответы [ 6 ]

7 голосов
/ 02 января 2011

Foreach - это довольно большое дело, его базовый метод - очень простой итератор только для пересылки, которому не нужно заранее знать, сколько элементов в коллекции. IEnumerator <>.

Что в целом является довольно неприятным несоответствием с ProgressBar. Вы можете существенно обновить стандартную версию, только если заранее знаете, сколько элементов вы повторяете. Таким образом, вы можете установить его свойство Maximum. Если это возможно , то у вас, без сомнения, есть доступ к свойству Count, а также индексатор. Который затем позволяет использовать оператор for (), проблема решена.

Но довольно часто вы заранее не представляете, сколько элементов нужно повторить. Типично для запросов к базе данных, например. Поскольку вы не можете узнать, сколько времени может потребоваться для итерации, у вас есть только одна опция на индикаторе выполнения: Style = Marquee. «Я не умер, я работаю» способ сообщить о прогрессе. Проблема решена.

6 голосов
/ 02 января 2011

Используйте for цикл вместо foreach.Это лучше в этой ситуации.

Используйте это так:

count = DirectoryFiles.Length;
for (int k = 0; k < count; k++)
{
    FileInfo file = DirectoryFiles[k];
    if ((file.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden || 
        (file.Attributes & FileAttributes.System) == FileAttributes.System)
    {
        continue;
    }

    backgroundWorkerLoadDir.ReportProgress(i, file.Name);
    System.Threading.Thread.Sleep(10);
}
2 голосов
/ 02 января 2011

Нет, это невозможно для IEnumerable, потому что он не имеет свойства Count / Length. Более того, вы можете легко представить бесконечную последовательность IEnumerable, например:

private readonly Random rand = new Random();
private IEnumerable<int> GetInfiniteRandomSequence() 
{
    while(true)
    {
        yield return rand.Next();
    }
}
1 голос
/ 05 июня 2013

Основным принципом для этой проблемы является следующее:

List<string> numbers = new List<string>() { "one", "two", "three" };

foreach (var num in numbers.Select((value, index) => new { value, index }))
{
    Console.WriteLine("Value: {0}, Index: {1}", num.value, num.index);
}

Это создаст новый анонимный тип в цикле foreach, содержащий value и index в переменной num.

Итак, чтобы решить проблему, указанную в ОП:

FileInfo[] directoryFiles = (new DirectoryInfo(folderBrowserDialog.SelectedPath)).GetFiles("*.*");
foreach (FileInfo file in directoryFiles.Select((value, index) => new {value, index}))
{
    if ((file.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden
          ||
        (file.Attributes & FileAttributes.System) == FileAttributes.System)
        continue;

    int progress = (file.index / DirectoryFiles.Length) * 100;

    backgroundWorkerLoadDir.ReportProgress(progress, file.value.Name);
    System.Threading.Thread.Sleep(10);
}
1 голос
/ 02 января 2011
using System.Linq;

for (var i = 0; i < items.Count(); i++)
{
    // Update progress bar here.
}
1 голос
/ 02 января 2011

Это ваш лучший вариант, потому что стандартные циклы for не работают на IEnumerable s, которые не индексируются. Если вам нужно узнать количество предметов, используйте свойство Count; если ни один не доступен, то, очевидно, по определению вы не можете знать заранее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...