Consider the following C#:
// C# .net
switch(x)
{
case 1:
for(int i = 0; i < 10; i++)
{
int val = getValue(i);
if (val == 0)
goto endswitch;
}
doMoreStuff();
break;
case 2:
doSomeThingElse();
break;
default: throw new ArgumentOutOfRangeException();
}
endswitch: ;
I've written code similar to the above code sample. The problem is that I need to break the switch statement from inside the inner for loop. If I put a break statement there, it will only break the inner for loop and then proceed to doMoreStuff(), which is not what I need.
The alternative that seems to work best here is a goto statement, but I know this is frowned upon.
Another alternative is to keep track of a separate variable inside the for loop, but this adds lines of code and is less elegent.
What is the best way to do this?
Update: I have read that there is a way to do this in JavaScript. It works like this: (http://www.devguru.com/technologies/ecmascript/quickref/break.html)
// JavaScript
outer_loop:
for(i=0; i<3; i++)
{
document.write("<BR>" + "outer " + i + ": ");
for(j=0; j<5; j++)
{
document.write("inner " + j + " ");
if(j==x)
break outer_loop;
}
}
Is something like this possible in C#?
You can abstract the check to a method with a return flag:
switch(x)
{
case 1:
if (ShouldDoMoreStuff())
doMoreStuff();
break;
case 2:
doSomeThingElse();
break;
default: throw new ArgumentOutOfRangeException();
}
private bool ShouldDoMoreStuff()
{
for(int i = 0; i < 10; i++)
{
var val = getValue(i);
if (val == 0)
return false;
}
return true;
}
Just to expand, you can use the goto as you had, but it's generally frowned upon, especially in such a trivial case. Sometimes it's useful when you have many, many nested loops or switches but that's usually a sign that maybe you should refactor/redesign a bit. As you pointed out, you can store a local variable and do a check but that's a bit obtuse/smelly as you realized. I prefer this method I posted above as it becomes pretty readable to work with.
EDIT: Regarding your comment and edited question, I do not believe a analogous language feature to your JavaScript code exists in C#. From http://msdn.microsoft.com/en-us/library/37zc9d2w%28VS.80%29.aspx (emphasis added):
Within nested statements, the break statement terminates only the do,
for, switch, or while statement that immediately encloses it. You can
use a return or goto statement to transfer control from within more
deeply nested structures.
This is the type of problem caused by too much thinking. You could simply have a boolean that will be altered if your condition is met before the for loop and run your method only if the boolean is true, e.g.:
switch(x)
{
case 1:
bool donrun;
for(int i = 0; i < 10; i++)
{
int val = getValue(i);
if (val == 0)
donrun = true;
}
if(!donrun) doMoreStuff();
break;
case 2:
doSomeThingElse();
break;
default: throw new ArgumentOutOfRangeException();
}
Related
I want to read a file containing comma-separated values, so have written a finite state machine:
private IList<string> Split(string line)
{
List<string> values = new List<string>();
string value = string.Empty;
ParseState state = ParseState.Initial;
foreach (char c in line)
{
switch (state)
{
case ParseState.Initial:
switch (c)
{
case COMMA:
values.Add(string.Empty);
break;
case QUOTE:
state = ParseState.Quote;
break;
default:
value += c;
state = ParseState.Data;
break;
}
break;
case ParseState.Data:
switch (c)
{
case COMMA:
values.Add(value);
value = string.Empty;
state = ParseState.Initial;
break;
case QUOTE:
throw new InvalidDataException("Improper quotes");
default:
value += c;
break;
}
break;
case ParseState.Quote:
switch (c)
{
case QUOTE:
state = ParseState.QuoteInQuote;
break;
default:
value += c;
break;
}
break;
case ParseState.QuoteInQuote:
switch (c)
{
case COMMA:
values.Add(value);
value = string.Empty;
state = ParseState.Initial;
break;
case QUOTE:
value += c;
state = ParseState.Quote;
break;
default:
throw new InvalidDataException("Unpaired quotes");
}
break;
}
}
switch (state)
{
case ParseState.Initial:
case ParseState.Data:
case ParseState.QuoteInQuote:
values.Add(value);
break;
case ParseState.Quote:
throw new InvalidDataException("Unclosed quotes");
}
return values;
}
Yes, I know the advice about CSV parsers is "don't write your own", but
I needed it quickly and
our download policy at work would take several days to allow me to
get open source off the 'net.
Hey, at least I didn't start with string.Split() or, worse, try using a Regex!
And yes, I know it could be improved by using a StringBuilder, and it's restrictive on quotes in the data, but
performance is not an issue and
this is only to generate well-defined test data in-house,
so I don't care about those.
What I do care about is the apparent trailing block at the end for mopping up all the data after the final comma, and the way that it's starting to look like some sort of an anti-pattern down there, which was exactly the sort of thing that "good" patterns such as a FSM were supposed to avoid.
So my question is this: is this block at the end some sort of anti-pattern, and is it something that's going to come back to bite me in the future?
All of the FSMs I've ever seen (not that I go hunting for them, mind you) all have some kind of "mopping up" step, simply due to the nature of enumeration.
In an FSM you're always acting upon the current state, and then resetting the 'current state' for the next iteration, so once you've hit the end of your iterations you have to do one last operation to act upon the 'current state'. (Might be better to think about it as acting upon the 'previous state' and setting the 'current state').
Therefore, I would consider that what you've done is part of the pattern.
But why didn't you try some of the other answers on SO?
Split CSV String (specifically this answer)
How to properly split a CSV using C# split() function? (specifically this answer)
Adapted solution, still an FSM:
public IEnumerable<string> fsm(string s)
{
int i, a = 0, l = s.Length;
var q = true;
for (i = 0; i < l; i++)
{
switch (s[i])
{
case ',':
if (q)
{
yield return s.Substring(a, i - a).Trim();
a = i + 1;
}
break;
// pick your flavor
case '"':
//case '\'':
q = !q;
break;
}
}
yield return s.Substring(a).Trim();
}
// === usage ===
var row = fsm(csvLine).ToList();
foreach(var column in fsm(csvLine)) { ... }
In a FSM you identify which states are the permitted halting states. So in a typical implementation, when you come out of the loop you need to at least check to make sure that your last state is one of the permitting halting states or throw a jam error. So having that one last state check outside of the loop is part of the pattern.
The source of the problem, if you want to call it that, is the absence of an end-of-line marker in your input data. Add a newline character, for example, at the end of your input string and you will be able to get rid of the "trailing block" that seems to annoy you so much.
As far as I'm concerned, your code is correct and, no, there is no reason why this implementation will come back to bite you in the future!
I had a similiar issue, but i was parsing a text file character by character. I didnt like this big clean-up-switch-block after the while loop. To solve this, I made a wrapper for the streamreader. The wrapper checked when streamreader had no characters left. In this case, the wrapper would return an EOT-ascii character once (EOT is equal to EOF). This way my state machine could react to the EOF depending on the state it was in at that moment.
This question already has answers here:
Break out of a while loop that contains a switch statement
(15 answers)
Closed 8 years ago.
I was asked to do maintenance work on some C# code which, I'm told, was originally converted from Visual Basic 6. (I mention this only because I don't know VB6 so I don't know if it would have made more sense in that language. . .)
It's got a for loop which parses some text for a proprietary scripting language by using a switch inside the for loop . . .
for ( t = 0; t < upperBound(tokens); t++)
{
String mystring = tokens[t];
switch (mystring)
{
case "GOTO":
if (firstGoto == -1)
{
firstGoto = t;
}
else
{
// compute number of tokens in GOTO
pointLength = t - firstGoto - 1;
break; // exit for
}
break;
case "ACTUATE"
. . .
Notice the comment
// exit for
The programmer expects the break will exit the for loop but I think it will only exit the switch statement because the documentation for break says
The break statement terminates the closest enclosing loop or switch statement in which it appears. Control is passed to the statement that follows the terminated statement, if any.
So am I correct that this will only exit the switch, but still be in the for, and if so, what is the correct way to do what the original programmer intended?
Yes, break will break out of the closest loop or switch. The easiest way is to use a goto. (No, goto is not evil)
for {
switch(...) {
....
goto MyLabel;
}
}
MyLabel:
Yes, you are correct... break will only exit the innermost block of code.
One easy way to do this is to also have a boolean flag which is set within the switch statement, and at the end of the loop just do this:
var flag = false;
for (...) {
switch (...) {
case "x":
flag = true;
}
if (flag) break;
}
Yes break will only terminate the switch in this scenario. How about using a boolean to exit the for as well..?
for ( t = 0; t < upperBound(tokens); t++)
{
String mystring = tokens[t];
bool exitFor = false;
switch (mystring)
{
case "GOTO":
if (firstGoto == -1)
{
firstGoto = t;
}
else
{
// compute number of tokens in GOTO
pointLength = t - firstGoto - 1;
exitFor = true;
break; // exit for
}
break;
case "ACTUATE"
. . .
if(exitFor)
break;
Is there an equivalent method of performing the job of redo in C#? i.e. going back to the top of the loop and re-execute without checking conditions or increasing the loop counter. Thanks.
for (int i = 0; i < 100; i++)
{
do
{
DoYourStuff();
} while (ShouldWeDoThatAgain());
}
Do...while is like a standard while loop, except instead of checking its conditional before each iteration, it checks after. That way, the code inside the loop will always execute at least once. Stick that inside a for or foreach loop, and that should get you the behavior your want. This is a bit simpler than Simon's answer, as it doesn't require an extra variable, doesn't use continue, and doesn't mess with the loop counter at all.
Why not simply:
Although goto is not really everyone's favourite, it's quite readable in this case...
for(...)
{
redo:
//...
if (...)
goto redo;
}
No. The closest you'll get is something like this:
bool redoCalled = false:
for (int i = 0; i < 10; i++) {
if (redoCalled) {
i--;
redoCalled = false;
}
// other stuff here
if (redoWanted) {
redoCalled = true;
continue;
}
}
JavaScript supports a goto like syntax for breaking out of nested loops. It's not a great idea in general, but it's considered acceptable practice. C# does not directly support the break labelName syntax...but it does support the infamous goto.
I believe the equivalent can be achieved in C#:
int i = 0;
while(i <= 10)
{
Debug.WriteLine(i);
i++;
for(int j = 0; j < 3; j++)
if (i > 5)
{
goto Break;//break out of all loops
}
}
Break:
By the same logic of JavaScript, is nested loop scenario an acceptable usage of goto? Otherwise, the only way I am aware to achieve this functionality is by setting a bool with appropriate scope.
My opinion: complex code flows with nested loops are hard to reason about; branching around, whether it is with goto or break, just makes it harder. Rather than writing the goto, I would first think really hard about whether there is a way to eliminate the nested loops.
A couple of useful techniques:
First technique: Refactor the inner loop to a method. Have the method return whether or not to break out of the outer loop. So:
for(outer blah blah blah)
{
for(inner blah blah blah)
{
if (whatever)
{
goto leaveloop;
}
}
}
leaveloop:
...
becomes
for(outer blah blah blah)
{
if (Inner(blah blah blah))
break;
}
...
bool Inner(blah blah blah)
{
for(inner blah blah blah)
{
if (whatever)
{
return true;
}
}
return false;
}
Second technique: if the loops do not have side effects, use LINQ.
// fulfill the first unfulfilled order over $100
foreach(var customer in customers)
{
foreach(var order in customer.Orders)
{
if (!order.Filled && order.Total >= 100.00m)
{
Fill(order);
goto leaveloop;
}
}
}
leaveloop:
instead, write:
var orders = from customer in customers
from order in customer.Orders;
where !order.Filled
where order.Total >= 100.00m
select order;
var orderToFill = orders.FirstOrDefault();
if (orderToFill != null) Fill(orderToFill);
No loops, so no breaking out required.
Alternatively, as configurator points out in a comment, you could write the code in this form:
var orderToFill = customers
.SelectMany(customer=>customer.Orders)
.Where(order=>!order.Filled)
.Where(order=>order.Total >= 100.00m)
.FirstOrDefault();
if (orderToFill != null) Fill(orderToFill);
The moral of the story: loops emphasize control flow at the expense of business logic. Rather than trying to pile more and more complex control flow on top of each other, try refactoring the code so that the business logic is clear.
I would personally try to avoid using goto here by simply putting the loop into a different method - while you can't easily break out of a particular level of loop, you can easily return from a method at any point.
In my experience this approach has usually led to simpler and more readable code with shorter methods (doing one particular job) in general.
Let's get one thing straight: there is nothing fundamentally wrong with using the goto statement, it isn't evil - it is just one more tool in the toolbox. It is how you use it that really matters, and it is easily misused.
Breaking out of a nested loop of some description can be a valid use of the statement, although you should first look to see if it can be redesigned. Can your loop exit expressions be rewritten? Are you using the appropriate type of loop? Can you filter the list of data you may be iterating over so that you don't need to exit early? Should you refactor some loop code into a separate function?
IMO it is acceptable in languages that do not support break n; where n specifies the number of loops it should break out.
At least it's much more readable than setting a variable that is then checked in the outer loop.
I believe the 'goto' is acceptable in this situation. C# does not support any nifty ways to break out of nested loops unfortunately.
It's a bit of a unacceptable practice in C#. If there's no way your design can avoid it, well, gotta use it. But do exhaust all other alternatives first. It will make for better readability and maintainability. For your example, I've crafted one such potential refactoring:
void Original()
{
int i = 0;
while(i <= 10)
{
Debug.WriteLine(i);
i++;
if (Process(i))
{
break;
}
}
}
bool Process(int i)
{
for(int j = 0; j < 3; j++)
if (i > 5)
{
return true;
}
return false;
}
I recommend using continue if you want to skip that one item, and break if you want to exit the loop. For deeper nested put it in a method and use return. I personally would rather use a status bool than a goto. Rather use goto as a last resort.
anonymous functions
You can almost always bust out the inner loop to an anonymous function or lambda. Here you can see where the function used to be an inner loop, where I would have had to use GoTo.
private void CopyFormPropertiesAndValues()
{
MergeOperationsContext context = new MergeOperationsContext() { GroupRoot = _groupRoot, FormMerged = MergedItem };
// set up filter functions caller
var CheckFilters = (string key, string value) =>
{
foreach (var FieldFilter in MergeOperationsFieldFilters)
{
if (!FieldFilter(key, value, context))
return false;
}
return true;
};
// Copy values from form to FormMerged
foreach (var key in _form.ValueList.Keys)
{
var MyValue = _form.ValueList(key);
if (CheckFilters(key, MyValue))
MergedItem.ValueList(key) = MyValue;
}
}
This often occurs when searching for multiple items in a dataset manually, as well. Sad to say the proper use of goto is better than Booleans/flags, from a clarity standpoint, but this is more clear than either and avoids the taunts of your co-workers.
For high-performance situations, a goto would be fitting, however, but only by 1%, let's be honest here...
int i = 0;
while(i <= 10)
{
Debug.WriteLine(i);
i++;
for(int j = 0; j < 3 && i <= 5; j++)
{
//Whatever you want to do
}
}
Unacceptable in C#.
Just wrap the loop in a function and use return.
EDIT: On SO, downvoting is used to on incorrect answers, and not on answers you disagree with. As the OP explicitly asked "is it acceptable?", answering "unacceptable" is not incorrect (although you might disagree).
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Breaking out of a nested loop
How to break out of 2 loops without a flag variable in C#?
Hello I have a function that has nested loops. Once the condition has been met, I want to break out of nested loops. The code is something like this below:
foreach (EmpowerTaxView taxView in taxViews)
{
foreach (PayrollEmployee payrollEmployee in payrollEmployees)
{
//PayStub payStub = payrollEmployee.InternalPayStub;
IReadOnlyList<PayrollWorkLocation> payrollWorkLocations = payrollEmployee.PayrollWorkLocations;
foreach (PayrollWorkLocation payrollWorkLocation in payrollWorkLocations)
{
Tax tax = GetTaxEntity(payrollWorkLocation, taxView.BSITypeCode, taxView.BSIAuthorityCode,
paidbyEr, resCode);
if (tax != null && tax.Rate.HasValue)
{
taxRate = tax.Rate.Value;
break;
}
}
}
}
Unfortunately, break comes out of only one loop. I want to break out of the whole thing. Please, I know some people have suggested goto: statement. I am wondering is there any other way around, such writing some LINQ queries to the same effect.
Any ideas and suggestions are greatly appreciated !
Two options suggest themselves as ways of getting out without having an extra flag variable to indicate "you should break out of the inner loop too". (I really dislike having such variables, personally.
One option is to pull all of this code into a separate method - then you can just return from the method. This would probably improve your code readability anyway - this really feels like it's doing enough to warrant extracting into a separate method.
The other obvious option is to use LINQ. Here's an example which I think would work:
var taxRate = (from taxView in taxViews
from employee in payrollEmployees
from location in employee.PayrollWorkLocations
let tax = GetTaxEntity(location, taxView.BSITypeCode,
taxView.BSIAuthorityCode,
paidbyEr, resCode)
where tax != null && tax.Rate.HasValue
select tax.Rate).FirstOrDefault();
That looks considerably cleaner than lots of foreach loops to me.
Note that I haven't selected tax.Rate.Value - just tax.Rate. That means the result will be a "null" decimal? (or whatever type tax.Rate is) if no matching rates are found, or the rate otherwise. So you'd then have:
if (taxRate != null)
{
// Use taxRate.Value here
}
Well, you could use the dreaded goto, refactor your code, or this:
// anon-method
Action work = delegate
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
return; // exits anon-method
}
}
};
work(); // execute anon-method
You could use a flag variable.
bool doMainBreak = false;
foreach (EmpowerTaxView taxView in taxViews)
{
if (doMainBreak) break;
foreach (PayrollEmployee payrollEmployee in payrollEmployees)
{
if (doMainBreak) break;
//PayStub payStub = payrollEmployee.InternalPayStub;
IReadOnlyList<PayrollWorkLocation> payrollWorkLocations = payrollEmployee.PayrollWorkLocations;
foreach (PayrollWorkLocation payrollWorkLocation in payrollWorkLocations)
{
Tax tax = GetTaxEntity(payrollWorkLocation, taxView.BSITypeCode, taxView.BSIAuthorityCode,
paidbyEr, resCode);
if (tax != null && tax.Rate.HasValue)
{
taxRate = tax.Rate.Value;
doMainBreak = true;
break;
}
}
}
}