How to leave a while loop inside a foreach loop - c#

I have a while loop and inside this while loop I have a foreach loop.
Here I learned how to skip the currently interaction on a loop by using Continue; Return; Break. But I need to leave the while loop when i'm inside the foreach loop is that possible ?
I'm on a interaction inside of the foreach loop and I want to leave the foreach and go to the next interaction of the while. How May I do that ?
Like so:
while (!reader.EndOfStream) //COMEÇO DO WHILE
{
///Some Codes
foreach(string s in checkedlistbox1.items)
{
switch(s)
{
case "1":
if( 1 > 0)
{
///HERE I WANT TO GO TO THE NEXT INTERACTION OF THE WHILE
///When I use CONTINUE; HERE, I GO TO THE NEXT INTERACTION OF THE FOREACH. BUT I NEED TO GO TO THE NEXT OF THE WHILE.
}
}
}
}
Here's what I want do to:
I'm reading a file.txt line by line, and writing a new one with these values and some others things... Some of these values may be required (seted by user), if a required fieldis empty, so I do nothing, and go to the next while interaction...

You need to break from the switch and then from the foreach, whilst having a variable set.
You can then check that variable to see whether you should continue to the next while iteration.
Do it like this:
while (!reader.EndOfStream)
{
// Some Codes
bool skipToNext = false;
foreach (string s in checkedlistbox1.items)
{
switch (s)
{
case "1":
if (1 > 0)
{
skipToNext = true;
break;
}
}
if (skipToNext) break;
}
// in the case of there being more code, you can now use continue
if (skipToNext) continue;
// more code
}
Example of this flow working
var list = new List<string> { "0", "1", "2" };
int a = 0, b = 2;
while (a++ < b)
{
// Some Codes
bool skipToNext = false;
foreach (string s in list)
{
Debug.WriteLine("{0} - {1}", a, s);
switch (s)
{
case "1":
if (1 > 0)
{
Debug.WriteLine("Skipping switch...");
skipToNext = true;
break;
}
}
if (skipToNext)
{
Debug.WriteLine("Skipping foreach...");
break;
}
}
// in the case of there being more code, you can now use continue
if (skipToNext)
{
Debug.WriteLine("Skipping to next while...");
continue;
}
// more code
}
Outputs:
1 - 0
1 - 1
Skipping switch...
Skipping foreach...
Skipping to next while...
2 - 0
2 - 1
Skipping switch...
Skipping foreach...
Skipping to next while...

bool dobreak = false;
while (!reader.EndOfStream && !dobreak ) //COMEÇO DO WHILE
{
///Some Codes
foreach(string s in checkedlistbox1.items)
{
switch(s)
{
case "1":
if( 1 > 0)
{
dobreak = true;
break;
}
}
}
}

1) Yes, it is possible. It works.
foreach() {
while() {
break; //leave the while
}
//... and continues from here
}
2) Each while will end before the next foreach iteration, so the second question does not make much sense... Unless you mean starting the next while inside the foreach, in which case.. yes!
foreach() {
while() {
...
}
break; //will go to the next foreach iteration, i.e. starts a new while
}
As for your code sample, a break in the point you mentioned in the comment will do what you need (exit the foreach, going naturally to the next while iteration).
EDIT: after you posted the example, it appears that your problem is not in the interaction between while and foreach, but in the switch: break is used as a keyword for both "go to the next iteration in the loop" and "finish this case and the switch".
The break will be seen by the compiler as a 'switch break'. You need to mimic the behavior by yourself:
foreach(string s in checkedlistbox1.items)
{
bool dobreak = false;
switch(s)
{
case "1":
if( 1 > 0)
{
dobreak = true;
}
break; // exit the case
}
if (dobreak)
break; // exits the for (it is a 'foreach-break')
}

Not tested, but these are a few possible ways which should answer your question:
bool continueLooping = true;
string[] array = { "1", "2" };
while (continueLooping)
{
foreach (string x in array)
{
// break out of foreach loop AND while loop
if (x == "1")
{
continueLooping = false;
break;
}
// go to next iteration of foreach loop
if (x == "2")
{
continue;
}
// break out of foreach loop and continue while loop
if (x == "3")
{
break;
}
}
}

You need to break from your foreach and the while so something like this:
bool abort = false;
while (!reader.EndOfStream && !abort) //COMEÇO DO WHILE
{
///Some Codes
foreach(string s in checkedlistbox1.items)
{
switch(s)
{
case "1":
if( 1 > 0)
{
///HERE I WANT TO LEAVE TO THE NEXT INTERACTION OF THE WHILE
abort = true;
break;
}
}
if (abort)
{
break;
}
}
}

I'm beginner in C#, but I suggest that you add another condition to the while loop that you can set yourself. Then, change it whenever is needed. For example:
MyKeyCondition = 0;
while(MainCondition||MyKeyCondition){
if(MyCheckCondition){
MyKeyCondition = 1;
}
}
Now, if you change your key condition, you can handle the while loop even if the main condition is not satisfied.

May try goto;
while (true)
{
foreach(string s in checkedlistbox1.items)
{
switch(s)
{
case "1":
if( 1 > 0)
{
goto WhileOut;
}
}
}
}
WhileOut:
// some code

Often nested loops are an indication that a method should be split up.
In this example, it could make the code clearer. If you place the inner for loop into a separate method, you can make that method return a bool. Return true if you want the outer while loop to continue iterating; otherwise, return false if you want it to exit the while loop.
It would look something like this:
private void doSomething(StreamReader reader)
{
while (!reader.EndOfStream)
{
// Some Codes...
if (!processNextItem(reader))
{
break;
}
}
}
// Returns true if the caller should continue its while loop; false if it should exit it.
private bool processNextItem(StreamReader reader)
{
foreach (string s in checkedlistbox1.items)
{
switch (s)
{
case "1":
if (1 > 0)
{
return false; // Return false to exit while loop.
}
}
}
return true; // Return true to continue while loop.
}
I'm not sure what you'd need to pass to processNextItem(); I've just passed reader as an example.

Related

C# if function criteria are fulfilled but not running linked code

I'm trying to finish a project, but the conditions I set in the if statement are fulfilled and not running the linked code. basically, I type null and it keeps running, even though it should set running to false, and it doesn't print the answer at the bottom. it's supposed to be a random number generator with variables linked to each number. I'm still new to C#, So I'm probably just using things wrong, as usual.
edit: added some fixes. also the line at the end, Console.WriteLine(answer) on line 99, is being considered unreachable, and it is the main way for me to know if my code works. if someone could let me know how to fix that, it would be great. also, could someone tell me some alternatives to the goto statement? edit 2: thanks for the help, It works now.
using System.Collections;
internal class Program
{
private static void Main(string[] args)
{
string item1;
string item2;
string item3;
string item4;
string item5;
string answer;
item1 = "";
item2 = "";
item3 = "";
item4 = "";
item5 = "";
answer = "";
bool Running = true;
while (Running)
{
Console.Write("Enter item 1: ");
item1 = Console.ReadLine();
Console.WriteLine("Enter item 2: ");
item2 = Console.ReadLine();
Console.WriteLine("Enter item 3, or type null: ");
item3 = Console.ReadLine();
if (item3 == "null" )
{
Running = false;
item3 = "";
}
Console.WriteLine("Enter item 4, or type null: ");
item4 = Console.ReadLine();
if (item4 == "null")
{
Running = false;
item4 = "";
}
Console.WriteLine("Enter item 5: ");
item5 = Console.ReadLine();
if (item5 == "null")
{
Running = false;
item5 = "";
}
}
reroll:
Random random = new Random();
switch (random.Next(1, 6))
{
case 1:
{
answer = item1;
break;
}
case 2:
{
answer = item2;
break ;
}
case 3:
{
if (item3 == "")
{
goto reroll;
}
answer = item3;
break;
}
case 4:
{
if (item4 == "")
{
goto reroll;
}
answer = item4;
break;
}
case 5:
{
if (item5 == "")
{
goto reroll;
}
answer = item5;
break;
}
Console.WriteLine(answer);
}
}
}
As far as your code is concerned I have several issues to bring up
When you feel the need to define variables like item1, item2, item3, etc then it is time to consider arrays and collections. You are learning bad habits otherwise. A fixed size array string[] items would suffice here, although a better solution would be to use a variable size List<string> items.
Try to divide up your code into functional parts, and use functions in order to minimize any possible side effects. This way you control the flow of information better.
If it all possible avoid goto, unless you absolutely need to. It makes code much harder to trace out and bugs are harder to catch. Alternatively use either a fixed count iteration like a for() loop, or a general while() statement and use the keyword break to exit the loop (or continue to move to the next iteration).
A lot of other smaller issues are a matter of experience with programming.
The way I read the code you are trying to do something like this
Enter Item 1
aaa
Enter Item 2
bbb
Enter Item 3
ccc
Enter Item 4 or press [ENTER] or type null to end.
ddd
Enter Item 5 or press [ENTER] or type null to end.
null
User List:
aaa
bbb
ccc
ddd
Randomly Selected Item: ddd
Here is one way of getting there using the principles laid out above. The code below is intended for learning purposes, with the hope that you are going to be able to follow along and understand what does what.
class Program
{
static readonly Random rng = new Random();
static void Main(string[] args)
{
// Get user inputs
string[] items = AskItemsFromUser(minItems:3, maxItems:5);
// Show what was entered as a list
Console.WriteLine("User List:");
Console.WriteLine(string.Join(Environment.NewLine, items));
Console.WriteLine();
// Show random item from list
string item = PickRandom(items);
Console.WriteLine($"Randomly Selected Item: {item}");
}
public static string[] AskItemsFromUser(int minItems, int maxItems)
{
List<string> items = new List<string>();
while (items.Count < maxItems)
{
// Change the prompt depending on the number of items entered.
if (items.Count >= minItems)
{
Console.WriteLine($"Enter Item {items.Count + 1} or press [ENTER] or type null to end.");
}
else
{
Console.WriteLine($"Enter Item {items.Count + 1}");
}
// get user input
string input = Console.ReadLine();
// if input=="null" or an empty string
if (input.Equals(string.Empty) || input.Equals("null"))
{
// and min # of items already reached
if (items.Count >= minItems)
{
// the exit loop
break;
}
}
else
{
// add user input to list
items.Add(input);
}
}
Console.WriteLine();
return items.ToArray();
}
public static string PickRandom(params string[] items)
{
// Use a random number generator to pick an item
// index = 0..count-1
int index = rng.Next(0, items.Length);
return items[index];
}
}

Execute multiple functions, but stop when an error occured

I want to use multiple functions after each other but if something went wrong in the first function the other functions shouldn't be executed. At the moment I'm using a while loop with a switch. Is there a way to skip the whole while/switch part with something else? Maybe something like an event?
while (!ErrorActive && iStep != 3)
{
switch (iStep)
{
case 0:
DoSomething(); // this can trigger ErrorActive
iStep = 1;
break;
case 1:
DoSomething2(); // this can trigger ErrorActive
iStep = 2;
break;
case 2:
DoSomething3(); // this can trigger ErrorActive
iStep = 3;
break;
}
}
the DoSomething functions have something like this:
public void DoSomething()
{
try
{
//calculate something
}
catch
{
ErrorActive = true;
}
}
Is there a way to skip the whole while/switch part and replace it with something else (like an event maybe?) or should I always keep something in between each function to check if everything is all right?
Just move the catch one level up:
// true if all steps executed, false otherwise
bool DoSteps()
{
int lastExecutedStep = 0;
try{
DoSomething();
lastExecutedStep = 1;
DoSomething1();
lastExecutedStep = 2;
DoSomething2();
lastExecutedStep = 3;
}
catch( IOException ioex )
{
// log IO Exception
}
// ... catch more expected exception types
return (lastExecutedStep == 3);
}
void DoSomething(){
// NO try/catch here
}
Even possible without stepcounter:
// true if all steps executed, false otherwise
bool DoSteps()
{
try{
DoSomething();
DoSomething1();
DoSomething2();
return true;
}
catch( IOException ioex )
{
// log IO Exception
}
// ... catch more expected exception types
return false;
}
For a more academical approach you may want to explore Chain of responsibility pattern
You can do as follows , why you use so mach code when solution is very simple.
if(!ErrorActive){
DoSomething(); // this can trigger ErrorActive
}
if(!ErrorActive){
DoSomething1(); // this can trigger ErrorActive
}
if(!ErrorActive){
DoSomething2(); // this can trigger ErrorActive
}
You can simplify the while loop to a for loop and make use of the new switch expression syntax to simplify things a bit. Also, have the functions return a success state rather than setting some shared variable:
void Run()
{
var keepRunning = true;
for(int i = 0; keepRunning; i++)
{
keepRunning = i switch
{
0 => DoSomething(),
1 => DoSomething2(),
2 => DoSomething3(),
_ => false
};
}
}
bool DoSomething()
{
try
{
return true;
}
catch
{
return false;
}
}
bool DoSomething2()
{
try
{
return true;
}
catch
{
return false;
}
}
bool DoSomething3()
{
try
{
return true;
}
catch
{
return false;
}
}

Faster way to compare enums?

I'm looking for a better way to compare enums. Currently, I have an enum with 3 different possible values:
public enum Elements { fire, water, earth };
However, an example of a function where something happens when two Elements collide:
Public Void ElementCollisionExample(Elements element1, Elements element2){
if (element1 == Elements.fire){
if (element2 == Elements.fire){
//Do stuff
} else if (element2 == Elements.water){
// Do stuff
} else {
// Do stuff
}
} else if (element2 == Elements.water){...etc...}
}
And that is only for the Fire Element!
I've searched a while, and looked on similar SO questions, but I'm not sure how to formulate the problem. All I've found are questions such as "Is '==' or '.Equals()' faster to compare Enums???", which is entirely different.
Is there an easy way to do this? I already have these conditions being handled in a separate Manager, but it still irritates me.
EDIT:
A combination of elements always has the same outcome. So Fire + Water = X, and Water + Fire = X as well.
It will be cleaner code with C# switch conditions introduced in C# 7.0.
public void ElementCollisionExample(Elements element1, Elements element2)
{
// Do nothing on equal elements
if (element1 == element2) return;
switch (element1)
{
case Elements.fire when element2 == Elements.water:
case Elements.water when element2 == Elements.fire:
// Do stuff
break;
case Elements.fire when element2 == Elements.earth:
case Elements.earth when element2 == Elements.fire:
// Do stuff
break;
case Elements.water when element2 == Elements.earth:
case Elements.earth when element2 == Elements.water:
// Do stuff
break;
}
}
Updated: Order of element1 and element2 does not matter. Also ignoring equal elements.
One option is to have a dictionary of actions you can invoke. For example:
public class ElementActionFactory
{
// Somewhere to keep our actions, using tuple to pair up elements
private Dictionary<(Elements, Elements), Action> _elementActions;
public ElementActionFactory()
{
// Initialise the action dictionary
_elementActions = new Dictionary<(Elements, Elements), Action>
{
{(Elements.Fire, Elements.Fire), FireAndFire},
{(Elements.Fire, Elements.Water), FireAndWater},
{(Elements.Fire, Elements.Earth), FireAndEarth},
// etc.
};
}
public void Invoke(Elements element1, Elements element2)
{
// Try to get the action, and if we don't find it...
if (!_elementActions.TryGetValue((element1, element2), out var action))
{
// reverse the arguments and try again - this assumes the order is not important
if (!_elementActions.TryGetValue((element2, element1), out action))
{
return; //No action was found
}
}
// Actually run the method now
action.Invoke();
}
public void FireAndFire()
{
Console.WriteLine("Fire And Fire");
}
public void FireAndWater()
{
Console.WriteLine("Fire And Water");
}
public void FireAndEarth()
{
Console.WriteLine("Fire And Earth");
}
}
And to use it, it's simply:
var elementActionFactory = new ElementActionFactory();
var element1 = Elements.Fire;
var element2 = Elements.Water;
elementActionFactory.Invoke(element1, element2);
Assuming that the order in which the elements are combined does not matter, you could treat the enumeration as a bit field, that is, a set of flags - so you can combine them allowing you to have a simple switch. For example:
[Flags]
public enum Elements
{
none = 0b0000_0000_0000,
fire = 0b0000_0000_0001,
water = 0b0000_0000_0010,
earth = 0b0000_0000_0100
};
public void ElementCollisionExample(Elements element1, Elements element2)
{
switch (element1 | element2)
{
case Elements.fire | Elements.water:
Console.WriteLine("The fire is extinguished");
break;
case Elements.earth | Elements.fire:
Console.WriteLine("The earth goes black");
break;
}
}
For Cleaner Code i suggest using complex switch ...
Elements x, y;
switch (x)
{
case Elements.fire:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.water:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.earth:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
}
With tuples, you can avoid the nested ifs:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(elements.Equals(Tuple.Create(Elements.fire, Elements.earth))
{
//do something
}
else if(elements.Equals(Tuple.Create(Elements.fire, Elements.water))
{
// do something
}
// and so on
}
You can simplify it more if you create a separate function:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(CompareElements(elements, Elements.fire, Elements.earth))
{
//do something
}
else if(CompareElements(elements, Elements.fire, Elements.water))
{
// do something
}
// and so on
}
private bool CompareElements(Tuple<Elements,Elements> actual, Elements expected1, Elements expected2)
{
return actual.Equals(Tuple.Create(expected1, expected2));
}

Why Driver.SwitchTo not always works in selenium?

I use the code
windowHandles = SeleniumHelper.WindowHandles();
// click...
if (SeleniumHelper.WindowHandles().Count > windowHandles.Count)
{
windowHandles = SeleniumHelper.WindowHandles();
while (pageTitle == SeleniumHelper.Driver.Title)
{
SeleniumHelper.Driver.SwitchTo().Window(windowHandles[windowHandles.Count - 1]);
Thread.Sleep(2000);
}
// do something...
SeleniumHelper.Driver.Close();
SeleniumHelper.BackToMainWindow();
}
The problem is that the driver finds the window, but does not switch to it.
Maybe there is a different way to switch to another window, like switch by javascript?
The problem is in
SeleniumHelper.Driver.SwitchTo().Window(windowHandles[windowHandles.Count - 1]);
You always switch to the last window regardless the while loop condition. Try this
string currentWindoe = SeleniumHelper.Driver.CurrentWindowHandle();
while (pageTitle != SeleniumHelper.Driver.Title)
{
SeleniumHelper.Driver.SwitchTo().Window(SeleniumHelper.Driver.CurrentWindowHandle());
Thread.Sleep(2000);
}
Or
string currentWindow = SeleniumHelper.Driver.CurrentWindowHandle();
foreach (string window in SeleniumHelper.Driver.WindowHandles())
{
if (!window.equals(currentWindow))
{
SeleniumHelper.Driver.SwitchTo().Window(window));
}
}

List<T>Get Chunk Number being executed

I am breaking a list into chunks and processing it as below:
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
do something
}
catch
{
print error
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this IEnumerable<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
foreach (var item in sourceList)
{
chunkReturn.Add(item);
if (chunkReturn.Count == chunkSize)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
if (chunkReturn.Any())
{
yield return chunkReturn;
}
}
}
If there is an error, I wish to run the chunk again. Is it possible to find the particular chunk number where we received the error and run that again ?
The batches have to be executed in sequential order .So if batch#2 generates an error, then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good .
List<Chunk> failedChunks = new List<Chunk>();
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
//do something
}
catch
{
//print error
failedChunks.Add(partiallist);
}
}
// attempt to re-process failed chunks here
I propose this answer based on your comment to Aaron's answer.
The batches have to be executed in sequential order .So if 2 is a problem , then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good.
foreach (var partialist in breaklistinchunks(chunksize))
{
int fails = 0;
bool success = false;
do
{
try
{
// do your action
success = true; // should be on the last line before the 'catch'
}
catch
{
fails += 1;
// do something about error before running again
}
}while (!success && fails < 2);
// exit the iteration if not successful and fails is 2
if (!success && fails >= 2)
break;
}
I made a possible solution for you if you don't mind switching from Enumerable to Queue, which kind of fits given the requirements...
void Main()
{
var list = new Queue<int>();
list.Enqueue(1);
list.Enqueue(2);
list.Enqueue(3);
list.Enqueue(4);
list.Enqueue(5);
var random = new Random();
int chunksize = 2;
foreach (var chunk in list.BreakListinChunks(chunksize))
{
foreach (var item in chunk)
{
try
{
if(random.Next(0, 3) == 0) // 1 in 3 chance of error
throw new Exception(item + " is a problem");
else
Console.WriteLine (item + " is OK");
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
list.Enqueue(item);
}
}
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this Queue<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
while(sourceList.Count > 0)
{
chunkReturn.Add(sourceList.Dequeue());
if (chunkReturn.Count == chunkSize || sourceList.Count == 0)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
}
}
Outputs
1 is a problem
2 is OK
3 is a problem
4 is a problem
5 is a problem
1 is a problem
3 is OK
4 is OK
5 is OK
1 is a problem
1 is OK
One possibility would be to use a for loop instead of a foreach loop and use the counter as a means to determine where an error occurred. Then you could continue from where you left off.
You can use break to exit out of the loop as soon as a chunk fails twice:
foreach (var partialList in breaklistinchunks(chunksize))
{
if(!TryOperation(partialList) && !TryOperation(partialList))
{
break;
}
}
private bool TryOperation<T>(List<T> list)
{
try
{
// do something
}
catch
{
// print error
return false;
}
return true;
}
You could even make the loop into a one-liner with LINQ, but it is generally bad practice to combine LINQ with side-effects, and it's not very readable:
breaklistinchunks(chunksize).TakeWhile(x => TryOperation(x) || TryOperation(x));

Categories