The goto
-keyword transfers control to a named label. It can be used to exit a deeply-nested loop. Goto can help us understand branches and control flow.
The goto
-statement is fairly powerful. We can use it in a loop or a switch
. In practice, many .NET developers never use goto
(except maybe in a switch
).
This program uses goto
to exit a nested loop. We can use code that does the same thing without goto
. But this would require a flag variable (usually a bool
) to check.
TestGotoNestedLoops
contains 3 nested loops. The first loop iterates through numbers [0, 9], as do the two inner loops.goto
keyword.goto
-statement should transfer control.using System; class Program { static void Main() { Console.WriteLine("RESULT: " + TestGotoNestedLoops()); } static int TestGotoNestedLoops() { // Part 1: 3 nested loops. int dummy = 0; for (int a = 0; a < 10; a++) { for (int y = 0; y < 10; y++) // Run until condition. { // Part 2: use if-statement in loop. // ... Then goto. for (int x = 0; x < 10; x++) // Run until condition. { if (x == 5 && y == 5) { goto Outer; } } dummy++; } // Part 3: the goto label. // ... Control ends up here. Outer: continue; } return dummy; } }RESULT: 50
break
We can rewrite code that uses goto
to use the break
and continue keywords. The goto
code uses one fewer variable.
using System; class Program { static void Main() { Console.WriteLine("BREAK: {0}", BreakMethod()); } static int BreakMethod() { int dummy = 0; for (int a = 0; a < 10; a++) { for (int y = 0; y < 10; y++) // Run until condition. { bool ok = true; for (int x = 0; x < 10; x++) // Run until condition. { if (x == 5 && y == 5) { ok = false; break; } } if (!ok) { break; } dummy++; } continue; } return dummy; } }BREAK: 50
Goto can be used in a switch
block. Switch allows control to be transferred to another case in this way. This use of goto
may be somewhat less confusing than others.
GetPrice()
performs 3 logical steps, all defined in the switch
-statement. We often find switches in single methods like this one.using System; class Program { static void Main() { Console.WriteLine(GetPrice(1000)); Console.WriteLine(GetPrice(-1)); Console.WriteLine(GetPrice(int.Parse("100"))); } static int GetPrice(int id) { // // Default price is 5. // int price = 5; // // When id is 1000, add 10 to price before multiplying. // switch (id) { case 1000: price += 10; // <-- Could get from another method goto case 100; case 100: return price * 10; default: return price; } // // 1. // First, if ID is 1000, add ten to default price. // // 2. // If ID is 1000 or 100, multiply price by 10 and return it. // // 3. // If ID is anything else, return price of 5. // } }150 5 50
goto
When we have a goto
, a matching label must be present. The label can be at the same scope level, or an enclosing scope (but not in a nested, enclosed scope).
using System; class Program { static void Main() { goto BIRD; Console.WriteLine("BIRD"); } }Error CS0159 No such label 'BIRD' within the scope of the goto statement
goto
If we have a label in a C# program that is not referenced, a warning will appear. This helps us keep our programs free of useless garbage statements.
using System; class Program { static void Main() { BIRD: Console.WriteLine("BIRD"); } }Warning CS0164 This label has not been referenced
goto
In my experience, it is best not to use goto
, even in switch
statements. Using a method to encapsulate logic is better—it is more versatile, and can promote code sharing better.
switch
Quality code is structured into discrete methods. We can call the same method with different values from a switch
.
goto
in switch
when trying to reduce method size. A benchmark shows this effect.string
constants here is that the low-level MSIL jump statement is used.Goto is part of the C# language. But usually it is not needed, and often teams will prefer to not allow it in programs. Consider polymorphism instead of goto
.