Foreach with continue -- unexpected behavior - c#

I'm trying to iterate over a atring to count the number of occurrences of a certain types of characters.
However, I'm not sure what the problem with my logic is.
foreach (var character in stringToCount)
{
if (char.IsLetterOrDigit(character))
{
alphaNumericCount++;
continue;
}
if (char.IsLower(character))
{
lowercaseCount++;
continue;
}
if (char.IsUpper(character))
{
uppercaseCount++;
continue;
}
}
Only the alphaNumericCount variable is being incremented, and any lowercase or uppercase character is being ignored. I think I've misunderstood the use of the continue keyword.
If I comment out the first if statement then somehow the lowercase and uppercase checks work.
What am I doing wrong?
Edit: Thank you everyone for your replies, they are all very good and informative. If I could award multiple correct answers I would!

The continue keyword jumps to the next letter in the string (the next foreach iteration). If you pass a lower case letter, it will increment in the first if statement, then move on to the next letter.
In your case, just remove the continue statements completely, and it will likely work as you expect.

continue breaks out of the foreach loop for the given item. Since any letter is alphanumeric, it hits the first continue and "jumps" out, never giving the other statements a chance to run.
In your case, it sounds like you should remove all instances of that keyword. In general, "jumping" out of loops like that should be done with caution, as it can cause bugs like this.
Note: break can be used in for and while loops to do the same thing, and comes with the same caution.

You should use else if:
foreach (var character in stringToCount)
{
if (char.IsLetterOrDigit(character))
{
alphaNumericCount++;
if (char.IsLower(character))
lowercaseCount++;
else if (char.IsUpper(character))
uppercaseCount++;
}
}
Because Continue skips the remaining code of the current iteration and jumps to the next iteration.

continue (C# Reference)
The continue statement passes control to the next
iteration of the enclosing while, do, for, or foreach statement in
which it appears.
From within a loop, you have two keywords that affect the flow of control:
break - Is like a goto END
continue - Is like a goto NEXT
In C#, the foreach() loop on an IEnumerable (or any object that provides a GetEnumerator() method with a proper enumerator object is implemented by first getting the enumerator object for the collection, visiting each item in the collection (enumerator) with enumerator.MoveNext(), and accessing that current item with enumerator.Current;
As a mental exercise, if you did not have foreach() or any other looping construct, you could implement it with goto and labels.
foreach(var item in container) // translates to lines 1 - 4 below
{
if(foo) continue; // line 5
if(bar) break; // line 6
// do something
}
translates to
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
As per the question, if you want to hit multiple conditions in the same loop, don't use continue at all; continue will skip everything after it for the current iteration. Use separate independent conditions so they all have the chance to execute.

This is by far the most readable method in my opinion:
int alphaNumericCount = stringToCount.Count(char.IsLetterOrDigit);
int lowercaseCount = stringToCount.Count(char.IsLower);
int uppercaseCount = stringtoCount.Count(char.IsUpper);
If you can't stand to repeat the iterations then:
foreach(var c in stringToCount.Where(char.IsLetterOrDigit))
{
++alphaNumericCount;
if (char.IsLower(c)) ++lowercaseCount;
if (char.IsUpper(c)) ++uppercaseCount;
}

Related

C# - How does a for loop understand the following syntax and why it works?

DOTNET FIDDLE
So, I left the for loop totally empty and did the following:
using System;
public class Program
{
public static void Main()
{
int i = 0;
for(;;){
if(i < 5){
Console.WriteLine(i);
i++;
}
else
{
break;
}
}
}
}
I knew that it would work, but I don't know how why it works. Could someone explain to me why this works and how the for loop understands that syntax?
I'm new to C# so take it easy on me.
There is no difference between for(;;) and while(true). You can use whatever you like.
Each part of a for loop (;;) contains a statement. As you know first section for initialization then condition checking and finally the increment/decrement section.
If you leave them empty then the loop will iterate for infinite times like it happens for while(true).
A for(...) loop with no initialization, condition, iteration step for(;;) is an Infinite Loop which runs forever unless an explicit exit condition given

Do .. While loop in C#?

How do I write a Do .. While loop in C#?
(Edit: I am a VB.NET programmer trying to make the move to C#, so I do have experience with .NET / VB syntax. Thanks!)
The general form is:
do
{
// Body
} while (condition);
Where condition is some expression of type bool.
Personally I rarely write do/while loops - for, foreach and straight while loops are much more common in my experience. The latter is:
while (condition)
{
// body
}
The difference between while and do...while is that in the first case the body will never be executed if the condition is false to start with - whereas in the latter case it's always executed once before the condition is ever evaluated.
Since you mentioned you were coming from VB.NET, I would strongly suggest checking out this link to show the comparisons. You can also use this wensite to convert VB to C# and vice versa - so you can play with your existing VB code and see what it looks like in C#, including loops and anything else under the son..
To answer the loop question, you simple want to do something like:
while(condition)
{
DoSomething();
}
You can also do - while like this:
do
{
Something();
}
while(condition);
Here's another code translator I've used with success, and another great C#->VB comparison website. Good Luck!
//remember, do loop will always execute at least once, a while loop may not execute at all
//because the condition is at the top
do
{
//statements to be repeated
} while (condition);
Quite surprising that no one has mentioned yet the classical example for the do..while construct. Do..while is the way to go when you want to run some code, check or verify something (normally depending on what happened during the execution of that code), and if you don't like the result, start over again. This is exactly what you need when you want some user input that fits some constraints:
bool CheckInput(string input) { ... }
...
string input;
...
do {
input=Console.ReadLine();
} while(!CheckInput(input));
That's quite a generic form: when the condition is simple enough, it's common to place it directly on the loop construct (inside the brackets after the "while" keyword), rather than having a method to compute it.
The key concepts in this usage are that you have to request the user input at least once (in the best case, the user will get it right at the first try); and that the condition doesn't really make much sense until the body has executed at least once. Each of these are good hints that do..while is the tool for the job, both of them together are almost a guarantee.
Here's a simple example that will print some numbers:
int i = 0;
do {
Console.WriteLine(++i);
} while (i < 10);
using System;
class MainClass
{
public static void Main()
{
int i = 0;
do
{
Console.WriteLine("Number is {0}", i);
i++;
} while (i < 100);
}
}
Another method would be
using System;
class MainClass
{
public static void Main()
{
int i = 0;
while(i <100)
{
Console.WriteLine("Number is {0}", i);
i++;
}
}
}
The answer by Jon Skeet is correct and great, though I would like to give an example for those unfamiliar with while and do-while in c#:
int i=0;
while(i<10)
{
Console.WriteLine("Number is {0}", i);
i++;
}
and:
int i=0;
do
{
Console.WriteLine("Number is {0}", i);
i++;
}while(i<10)
will both output:
Number is 0
Number is 1
Number is 2
Number is 3
Number is 4
Number is 5
Number is 6
Number is 7
Number is 8
Number is 9
as we would expect. However it is important to understand that the do-while loop always executes the body the first time regardless of the check. This means that if we change i's starting value to 100 we will see very different outputs.
int i=100;
while(i<10)
{
Console.WriteLine("Number is {0}", i);
i++;
}
and:
int i=100;
do
{
Console.WriteLine("Number is {0}", i);
i++;
}while(i<10)
Now the while loop actually generates no output:
however the do-while loop generates this:
Number is 100
despite being well over 10. This is because of the unique behavior of a do-while loop to always run once unlike a regular while loop.
Apart from the Anthony Pegram's answer, you can use also the while loop, which checks the condition BEFORE getting into the loop
while (someCriteria)
{
if (someCondition)
{
someCriteria = false;
// or you can use break;
}
if (ignoreJustThisIteration)
{
continue;
}
}

C# yield return not returning an item as expected

I have following code:
private void ProcessQueue()
{
foreach (MessageQueueItem item in GetNextQueuedItem())
PerformAction(item);
}
private IEnumerable<MessageQueueItem> GetNextQueuedItem()
{
if (_messageQueue.Count > 0)
yield return _messageQueue.Dequeue();
}
Initially there is one item in the queue as ProcessQueue is called.
During PerformAction, I would add more items to _messageQueue. However, the foreach loop quits after the initial item and does not see the subsequent items added.
I sense that somehow the initial state of the queue is being captured by yield.
Can someone explain what is happening and give a solution?
Your program does exactly what you instructed to do: it yields one item if Count > 0 - and yields zero items otherwise.
To return items until the queue becomes empty, try:
while (_messageQueue.Count > 0)
yield return actually pauses execution and does a fake return (it yields a value) until the next one is requested. In this case, what happens is you check if the count is > 0 and then yield the next value. When the next one is requested, your if statement isn't checked again, it returns to the line after the yield return which is the end of the method and thus it's done.
The definition of "YIELD"
Used in an iterator block to provide a value to the enumerator object or to signal the end of iteration.
I have an excellent record of reading syntax statements wrong but I think this means it has to be in an iterator block and the one you wrote is not.
Perhaps change your code to;
foreeach (MessageQueItem item In GetNextQuedItem()
{
if (_messageQueue.Count > 0)
{
yield return _messageQueue.Dequeue();
} else {
yield break;
}
}

C# , what behavior does continue in a while produce?

I have a C# while loop, does a continue in this loop issue the same behaviour as moving to the next item in the loop? Exactly the same as for a "for loop".
For example see any problems in the following code sample?
while ((line = file.ReadLine()) != null)
{
string messageDownloadID = line ;
if (String.IsNullOrEmpty(messageDownloadID))
{
continue;
}
}
Thanks in advance.
I have a C# while loop, does a continue in this loop issue the same behaviour as moving to the next item in the loop? Exactly the same as for a "for loop".
No, a continue does not have the behavior of moving to the next item unless the part of the while block that moves to the next item is part of the loop condition or occurs and is executed before the continue statement. A continue will move you to the next iteration of the loop. The continue statement always starts a new iteration in the nearest enclosing while, do, for or foreach statement. But if in a while loop, say, i++ occurs after the continue statement it will not be executed. It is NOT exactly the same as a for loop.
The semantics of continue are like so:
while(condition) {
statement
continue
statement
}
is equivalent to
top:
while(condition) {
statement
goto top;
statement
}
In this case, the statements after the continue will never be executed if the continue is executed. But, for example, these two loops have different semantics:
for (int i = 0; i < 10; i++) {
if (i == 5) {
continue;
}
Console.WriteLine(i);
}
int j = 0;
while (j < 10) {
if (j == 5) {
continue;
}
Console.WriteLine(j);
j++;
}
The former loop will print 0 through 9 on the console while the second will enter an infinite loop after print 0 through 4 on the console.
For example see any problems in the following code sample?
while ((line = file.ReadLine()) != null) {
string messageDownloadID = line;
if (String.IsNullOrEmpty(messageDownloadID)) {
continue;
}
}
Well, it depends. First, this loop isn't doing anything really except moving the file pointer in file to the end of the file. Now, assuming that you meant to have statements after the if statement like so
while ((line = file.ReadLine()) != null) {
string messageDownloadID = line;
if (String.IsNullOrEmpty(messageDownloadID)) {
continue;
}
ProcessMessageDownloadID(messageDownloadID);
}
then your code is fine. This is because the part of the while that moves to the next item is part of the while condition (see my bolded statement above) and thus will be executed every iteration of the loop. Your code is a standard pattern for parsing a file and skipping over items that can't be parsed (because they are, say, blank).
Yes, continue moves to the next iteration of the loop.
Yes, a continue call will restart the loop. Kind of like a goto to a label at the start of the loop.
Yes.
"A while loop can be terminated when a break, goto, return, or throw statement transfers control outside the loop. To pass control to the next iteration without exiting the loop, use the continue statement."

Continue in while inside foreach

In the following C# code snippet
I have a 'while' loop inside a 'foreach' loop and I wish to jump to the next item in 'foreach' when a certain condition occurs.
foreach (string objectName in this.ObjectNames)
{
// Line to jump to when this.MoveToNextObject is true.
this.ExecuteSomeCode();
while (this.boolValue)
{
// 'continue' would jump to here.
this.ExecuteSomeMoreCode();
if (this.MoveToNextObject())
{
// What should go here to jump to next object.
}
this.ExecuteEvenMoreCode();
this.boolValue = this.ResumeWhileLoop();
}
this.ExecuteSomeOtherCode();
}
'continue' would jump to the beginning of the 'while' loop not the 'foreach' loop.
Is there's a keyword to use here, or should I just use goto which I don't really like.
Use the break keyword. That will exit the while loop and continue execution outside it. Since you don't have anything after the while, it would loop around to the next item in the foreach loop.
Actually, looking at your example more closely, you actually want to be able to advance the for loop without exiting the while. You can't do this with a foreach loop, but you can break down a foreach loop to what it actually automates. In .NET, a foreach loop is actually rendered as a .GetEnumerator() call on the IEnumerable object (which your this.ObjectNames object is).
The foreach loop is basically this:
IEnumerator enumerator = this.ObjectNames.GetEnumerator();
while (enumerator.MoveNext())
{
string objectName = (string)enumerator.Value;
// your code inside the foreach loop would be here
}
Once you have this structure, you can call enumerator.MoveNext() within your while loop to advance to the next element. So your code would become:
IEnumerator enumerator = this.ObjectNames.GetEnumerator();
while (enumerator.MoveNext())
{
while (this.ResumeWhileLoop())
{
if (this.MoveToNextObject())
{
// advance the loop
if (!enumerator.MoveNext())
// if false, there are no more items, so exit
return;
}
// do your stuff
}
}
The following should do the trick
foreach (string objectName in this.ObjectNames)
{
// Line to jump to when this.MoveToNextObject is true.
this.ExecuteSomeCode();
while (this.boolValue)
{
if (this.MoveToNextObject())
{
// What should go here to jump to next object.
break;
}
}
if (! this.boolValue) continue; // continue foreach
this.ExecuteSomeOtherCode();
}
The break; keyword will exit a loop:
foreach (string objectName in this.ObjectNames)
{
// Line to jump to when this.MoveToNextObject is true.
while (this.boolValue)
{
// 'continue' would jump to here.
if (this.MoveToNextObject())
{
break;
}
this.boolValue = this.ResumeWhileLoop();
}
}
Use goto.
(I guess people will be mad with this response, but I definitely think it's more readable than all other options.)
You can use "break;" to exit the innermost while or foreach.

Categories

Resources