2014-09-26 3 views
1

Я пытаюсь выполнить итерацию по строке, чтобы подсчитать количество вхождений определенных типов символов.Foreach with continue - неожиданное поведение

Однако я не уверен, в чем проблема с моей логикой.

foreach (var character in stringToCount) 
{ 
    if (char.IsLetterOrDigit(character)) 
    { 
     alphaNumericCount++; 
     continue; 
    } 

    if (char.IsLower(character)) 
    { 
     lowercaseCount++; 
     continue; 
    } 

    if (char.IsUpper(character)) 
    { 
     uppercaseCount++; 
     continue; 
    } 
} 

только переменная alphaNumericCount инкрементируются, и любые нижние или верхний регистр символы игнорируются. Я думаю, что неправильно понял ключевое слово continue.

Если я прокомментирую первый оператор if, то почему-то строчные и прописные чеки работают.

Что я делаю неправильно?

Редактировать: Спасибо всем за ваши ответы, все они очень хороши и информативны. Если бы я мог присудить несколько правильных ответов, я бы!

+5

Если символ верхнего или нижнего регистра, то все еще письмо, не так ли? :) Возьмите 'continue' из первого оператора if. –

+0

просто избавьтесь от 'continue'. вам не нужны они –

+6

** Пройдите код в отладчике ** - для чего он нужен. Ваша ошибка станет очевидной примерно через пять секунд после этого. –

ответ

5

continue выходит из цикла foreach для данного элемента. Так как любая буква является буквенно-цифровой, она ударяет по первому продолжению и «перескакивает», не давая другим операторам возможность запускать.

В вашем случае это звучит так, как будто вы должны удалить все экземпляры этого ключевого слова. В общем, «прыгать» из таких циклов следует делать с осторожностью, так как это может вызвать такие ошибки.

Примечание: break может использоваться в for и while петлях, чтобы сделать то же самое, и поставляется с той же осторожностью.

+1

'breaks' может не быть лучшим словом для использования, так как' break' - полностью отдельная команда. –

+0

@ColinDeClue Вот как я могу сказать это при разговоре с другим программистом. Тем не менее, я изменил его, чтобы попытаться избежать путаницы. Спасибо за комментарий! Кстати, 'break' имеет почти то же поведение, что и' continue' (хотя он полностью выходит из цикла) – BradleyDotNET

6

Ключевое слово continue переходит к следующей букве в строке (следующая итерация foreach). Если вы передадите строчную букву, она будет увеличиваться в первом выражении if, а затем перейти к следующей букве.

В вашем случае просто удалите заявления continue, и он, скорее всего, будет работать так, как вы ожидаете.

3

Вы должны использовать else if:

foreach (var character in stringToCount) 
{ 
    if (char.IsLetterOrDigit(character)) 
    { 
     alphaNumericCount++; 

     if (char.IsLower(character)) 
      lowercaseCount++; 

     else if (char.IsUpper(character)) 
      uppercaseCount++; 
    } 
} 

Continue Поскольку скачет оставшийся код текущей итерации и переходит к следующей итерации.

+3

Это вызовет ту же проблему, что и оригинал. '' a'' не будет увеличивать 'lowercaseCount' :) –

+0

@ReedCopsey Спасибо за указание :) – Shaharyar

+0

' else if' предпочитает 'продолжать ', когда вы * хотите * это поведение, хотя оно не нарушает выполнение течь. Не правильно для этой ситуации, но хороший совет в целом! – BradleyDotNET

2

продолжает (Справочник по C#)

Продолжить утверждение передает управление следующего итерации вмещающего времени, делать, ибо, или заявление Еогеаспа в котором он появляется.

С внутри цикла, то есть два ключевых слова, которые влияют на поток управления:

  1. перерыв - Это как Гото END
  2. продолжать - Это как Goto Next

В C# цикл foreach() в IEnumerable (или любой объект, предоставляющий метод GetEnumerator() с соответствующим объектом перечисления, реализуется путем первого получения объекта перечислителя для коллекции, посещения каждого элемента в коллекции (enumerator) с enumerator.MoveNext() и доступ к этому текущему элементу с помощью enumerator.Current;

Как умственное упражнение, если вы не имеете Еогеасп() или любой другой для создания циклов, вы можете реализовать его с Гото и этикетки.

foreach(var item in container) // translates to lines 1 - 4 below 
{ 
    if(foo) continue;   // line 5 
    if(bar) break;    // line 6 
    // do something 
} 

переводит

1:  var enumerator = container.GetEnumerator(); // initialize the enumerator 
2: next: if(enumerator.MoveNext()) 
3:  { 
4:   var item = enumerator.Current; // get item to work on (the "topic") 
5:   if(foo) goto next;    // 'continue' keyword - skips to next 
6:   if(bar) goto end;    // 'break' keyword - exits loop 
7:   // do something 
8:   goto next;      // normal loop iteration to next item 
9:  }  
10: end:          // loop done 

По вопросу, если вы хотите ударить несколько условий в одном цикле, не использовать по-прежнему на всех; continue будет пропускать все после него для текущей итерации. Используйте отдельные независимые условия, чтобы все они имели возможность выполнить.

1

Это, безусловно, самый читаемый метод, на мой взгляд:

int alphaNumericCount = stringToCount.Count(char.IsLetterOrDigit); 
int lowercaseCount = stringToCount.Count(char.IsLower); 
int uppercaseCount = stringtoCount.Count(char.IsUpper); 

Если вы не можете стоять повторять итерации, то:

foreach(var c in stringToCount.Where(char.IsLetterOrDigit)) 
{ 
    ++alphaNumericCount; 
    if (char.IsLower(c)) ++lowercaseCount; 
    if (char.IsUpper(c)) ++uppercaseCount; 
} 
Смежные вопросы