Is there a reason to use goto in modern .NET code?

I just found this code in the reflector in the .NET base libraries ...

if (this._PasswordStrengthRegularExpression != null) { this._PasswordStrengthRegularExpression = this._PasswordStrengthRegularExpression.Trim(); if (this._PasswordStrengthRegularExpression.Length == 0) { goto Label_016C; } try { new Regex(this._PasswordStrengthRegularExpression); goto Label_016C; } catch (ArgumentException exception) { throw new ProviderException(exception.Message, exception); } } this._PasswordStrengthRegularExpression = string.Empty; Label_016C: ... //Other stuff 

I heard everything that "you should not use goto for fear of exile to hell for eternity." I have always adhered to MS encoders in a rather high regard, and although I may not have agreed with all their decisions, I always respected their reasoning.

So - is there a good reason for such code that I am missing? Was this piece of code simply compiled by an inept developer? or does the .NET reflector return inaccurate code?

I hope there is a good reason, and I just blindly missed it.

Thank you all for entering.

+30
c # goto
Mar 30 '10 at 1:25
source share
19 answers

The reflector is not perfect. The actual code for this method is available from a reference source. It is located in ndp \ fx \ src \ xsp \ system \ web \ security \ admembershipprovider.cs:

  if( passwordStrengthRegularExpression != null ) { passwordStrengthRegularExpression = passwordStrengthRegularExpression.Trim(); if( passwordStrengthRegularExpression.Length != 0 ) { try { Regex regex = new Regex( passwordStrengthRegularExpression ); } catch( ArgumentException e ) { throw new ProviderException( e.Message, e ); } } } else { passwordStrengthRegularExpression = string.Empty; } 

Notice how the last else clause was not found and compensated with goto. This is almost certainly blocked by try / catch blocks inside if () statements.

Obviously, you will want to use the source code instead of the decompiled version. The comments themselves are quite useful, and you can count on the source being accurate. Well, mostly accurate, there is little damage from the buggy post-processing tool that removed the names of Microsoft programmers. Identifiers are sometimes replaced by dashes, and the code is repeated twice. You can download the source here .

+42
Mar 30 '10 at 2:09
source share

Most likely, it is not in the source code, this is how the disassembled code looks.

+12
Mar 30 '10 at 1:37
source share

I saw that goto is used to exit nested loops:

How can I break out of two nested loops in Objective-C?

I see nothing wrong with using it that way.

+12
Mar 30 '10 at 1:48
source share

There are several valid uses for goto in .NET (C #):

Simulated switch expression "Falling semantics . "

Those that come from the C ++ background are used to write switch statements that automatically switch from case to case, unless explicitly terminated with break. For C #, only trivial (empty) cases are possible.

For example, in C ++

 int i = 1; switch (i) { case 1: printf ("Case 1\r\n"); case 2: printf ("Case 2\r\n"); default: printf ("Default Case\r\n"); break; } 

In this C ++ code, the output is:

 Case 1
 Case 2
 Default case

Here is a similar C # code:

 int i = 1; switch (i) { case 1: Console.Writeline ("Case 1"); case 2: Console.Writeline ("Case 2"); default: Console.Writeline ("Default Case"); break; } 

As written, this will not compile. There are several compilation errors that look like this:

 Control cannot fall through from one case label ('case 1:') to another

Adding goto statements does the job:

 int i = 1; switch (i) { case 1: Console.WriteLine ("Case 1"); goto case 2; case 2: Console.WriteLine("Case 2"); goto default; default: Console.WriteLine("Default Case"); break; } 

... another useful use of goto in C # is ...

Endless loops and extended recursion

I will not go into details here, since it is less useful, but sometimes we write endless loops using while(true) constructors that explicitly terminate with break or re-execute with the continue statement. This can happen when we try to simulate calls to recursive methods, but have no control over the potential scope of the recursion.

You can obviously convert this to a while(true) or reorganize it into a separate method, but also use the label and goto statement.

This use of Goto is more controversial, but still something is worth keeping in mind as an option in very rare cases.

+9
Jul 02 2018-10-02T00:
source share

I'm not crazy about gotos, but to say that they are never true is silly.

I used it once to fix a defect in a particularly dirty part of the code. To reorganize the code and test it, it would not be practical given the time limit.

Also, haven't we all seen conditional constructs that were so poorly coded that they make gotos seem benign?

+8
Mar 30 '10 at 5:22
source share

You should not look at the reflector code.

Although if you ever look at the disassembled IL, you will see everything around the place. In fact, all the loops and other control constructs that we use are converted to gotos anyway, simply because turning them into constructs in our code makes it more readable and easier to maintain.

I don't think the code you posted would be a good place to use goto, by the way, and I can't think about it.

+4
Mar 30
source share

You can use GOTO to do recursion with better performance. It is much more difficult to maintain, but if you need these extra cycles, you can pay the burden of maintenance.

Here is a simple example with the results:

 class Program { // Calculate (20!) 1 million times using both methods. static void Main(string[] args) { Stopwatch sw = Stopwatch.StartNew(); Int64 result = 0; for (int i = 0; i < 1000000; i++) result += FactR(20); Console.WriteLine("Recursive Time: " + sw.ElapsedMilliseconds); sw = Stopwatch.StartNew(); result = 0; for (int i = 0; i < 1000000; i++) result += FactG(20); Console.WriteLine("Goto Time: " + sw.ElapsedMilliseconds); Console.ReadLine(); } // Recursive Factorial static Int64 FactR(Int64 i) { if (i <= 1) return 1; return i * FactR(i - 1); } // Recursive Factorial (using GOTO) static Int64 FactG(Int64 i) { Int64 result = 1; Loop: if (i <= 1) return result; result *= i; i--; goto Loop; } 

Here are the results that I get on my machine:

  Recursive Time: 820 Goto Time: 259 
+4
Jul 02 '10 at 17:28
source share

I have not seen the actual case for Goto in the many, many lines of .NET code that have been written and reviewed.

In languages ​​that do not support structured exception handling with a finally block (PASCAL is the grandfather of structured programming languages, as well as classic C), tactical use of GOTO can lead to a significant understanding of the code when used to perform cleaning, when execution completes inside nested loops (in as opposed to correctly setting several conditions for terminating the cycle) Even on the same day, I did not use goto personally for this reason (probably out of fear of “exile to hell forever”).

+3
Mar 30 '10 at 1:32
source share

Goto is often useful when writing parsers and lexers.

+3
Mar 30
source share

No, there is no good reason to use goto . I last coded the goto in 1981, and I have not missed this particular construct since.

+2
Mar 30
source share

In addition to all of these good real things, when you look at the parsed code, keep in mind that the PRAY developers used the obfuscator on these assemblies. One obfuscation technique is to add random goto to IL

+2
Mar 30 '10 at 1:50
source share

Take a look at the state diagram. If you think that the best code structure to use is the one that most directly and clearly expresses your intention, then each of these state transitions should be encoded as goto.

This tends to break in the real world. The first problem is that we often have to stop the machine, exit to another code and resume the machine later — this means that each of these transitions tends to be a change in the state variable used to determine the correct state in the / case statement switch. This is actually just a way to hide and delay goto - writing a state variable is not much different than writing to a program counter register. It's just a way to implement "goto there", but not now, later. "

However, there are cases when goto works well to express what is happening in some state model - I would suggest that one of those diagnostic flowcharts that doctors sometimes use is an example. If you implement one of them as a program without using transitions for transitions, then in fact you just make life difficult for yourself by encrypting the intent of your code.

It is just that the most common cases are unlikely to be hand-written. I wrote code generators that generate goto statements for transitions in different types of state models (solution processing, regular grammar analysis, etc.), but I don’t remember the last time I used goto in handwritten code.

+2
Mar 30 '10 at 1:55
source share

In relation to this point:

So - is there a good reason for code like this that I am missing? Was it code extraction, just compiled by a crappy developer? Or is .NET reflector returning inaccurate code?

I disagree with the suggestion that these are the only three possibilities.

Perhaps this is true, as many others have suggested, that this is simply not an accurate reflection of the actual source code in the library. Despite everything, we were all guilty (well, in any case, I did) wrote the code "dirty way" with the goal:

  • Quick function implementation
  • Quick bug fix.
  • Squeezing a small increase in productivity (sometimes with justification, sometimes not so much)
  • Some other reason that made sense at the time

This does not make anyone a "crappy developer." Most guides, such as "do not use goto," are mainly created to protect developers from themselves; they should not be seen as the key to distinguishing between good and bad developers.

As an analogy, consider the simple rule that many of us learn at an English school: never end a sentence with a preposition. This is not a real rule. ; this guide is to help people not say things like "Where is the car?" It is important to understand this fact; as soon as you begin to regard it as an actual rule, instead of leadership, you will find that you “correct” people for completely good sentences, such as “What are you afraid of?”

Given this, I would be wary of any developer who called another developer "shitty" because he used goto .

Of course, I am not trying to defend goto as such, simply by asserting that its use does not mean incompetence by any means.

+2
Mar 30 '10 at 4:51
source share

There is one valid case - when you try to simulate a call to a recursive procedure and return in non-recursive code or do something similar (this kind of requirement also occurs in the Prolog interpreter). But in general, if you are not doing something that requires micro-optimization, for example, a chess program or a language translator, it is much better to just use the stack of the usual procedure and use function / procedure calls.

0
Mar 30 '10 at 1:36
source share

goto is great for cleaning files in languages ​​like C, at least where it mimics the concept of exceptions somewhat. I'm sure .NET has better ways to handle these things, so goto is just out of date and error prone.

0
Mar 30 '10 at 2:02
source share

I do not like this code.

I would prefer to keep Regex in a member and check it when setting it up, while avoiding the need for all the logic.

0
Mar 30 '10 at 2:12
source share

As others have shown, the code that you see in the reflector is necessarily code that is written in the Framework. The compiler and optimizers can change the code to what works in the same way, if it does not change the actual work performed by the code. You should also indicate that the compiler implements all branches and loops as goto (branches in IL or jumps in the assembly.) When the release mode is launched and the compiler tries to optimize the code in the simplest form, functionally the same as your source.

I have an example on various loop methods that all compiled to 100% of the same IL when you compile for release. See Another Answer

(I can't find it right now, but Eric Lippert wrote a note on how the C # compiler handles code. One of the points he did is how all the loops change to goto's.)

Saying I have no problem with goto. If there is a better loop structure, use it. But sometimes you need something a little bit, something that you can squeeze because of, foreach, for now, do / while, but you don’t want the added mess and pain arising from method calls (why spend 5 plus lines so that convert nested to recursive methods.)

0
Mar 30 '10 at 11:34
source share

This is not a good example, but it shows a case where goto can be very convenient.

 private IDynamic ToExponential(Engine engine, Args args) { var x = engine.Context.ThisBinding.ToNumberPrimitive().Value; if (double.IsNaN(x)) { return new StringPrimitive("NaN"); } var s = ""; if (x < 0) { s = "-"; x = -x; } if (double.IsPositiveInfinity(x)) { return new StringPrimitive(s + "Infinity"); } var f = args[0].ToNumberPrimitive().Value; if (f < 0D || f > 20D) { throw new Exception("RangeError"); } var m = ""; var c = ""; var d = ""; var e = 0D; var n = 0D; if (x == 0D) { f = 0D; m = m.PadLeft((int)(f + 1D), '0'); e = 0; } else { if (!args[0].IsUndefined) // fractionDigits is supplied { var lower = (int)Math.Pow(10, f); var upper = (int)Math.Pow(10, f + 1D); var min = 0 - 0.0001; var max = 0 + 0.0001; for (int i = lower; i < upper; i++) { for (int j = (int)f;; --j) { var result = i * Math.Pow(10, j - f) - x; if (result > min && result < max) { n = i; e = j; goto Complete; } if (result <= 0) { break; } } for (int j = (int)f + 1; ; j++) { var result = i * Math.Pow(10, j - f) - x; if (result > min && result < max) { n = i; e = j; goto Complete; } if (result >= 0) { break; } } } } else { var min = x - 0.0001; var max = x + 0.0001; // Scan for f where f >= 0 for (int i = 0;; i++) { // 10 ^ f <= n < 10 ^ (f + 1) var lower = (int)Math.Pow(10, i); var upper = (int)Math.Pow(10, i + 1D); for (int j = lower; j < upper; j++) { // n is not divisible by 10 if (j % 10 == 0) { continue; } // n must have f + 1 digits var digits = 0; var state = j; while (state > 0) { state /= 10; digits++; } if (digits != i + 1) { continue; } // Scan for e in both directions for (int k = (int)i; ; --k) { var result = j * Math.Pow(10, k - i); if (result > min && result < max) { f = i; n = j; e = k; goto Complete; } if (result <= i) { break; } } for (int k = (int)i + 1; ; k++) { var result = i * Math.Pow(10, k - i); if (result > min && result < max) { f = i; n = j; e = k; goto Complete; } if (result >= i) { break; } } } } } Complete: m = n.ToString("G"); } if (f != 0D) { m = m[0] + "." + m.Substring(1); } if (e == 0D) { c = "+"; d = "0"; } else { if (e > 0D) { c = "+"; } else { c = "-"; e = -e; } d = e.ToString("G"); } m = m + "e" + c + d; return new StringPrimitive(s + m); } 
0
Jul 02 '10 at 3:05 a.m.
source share

I did not even encode GO TO back when I wrote FORTRAN.

I never had to use it. I do not understand why any modern language will require such a thing from the user. I would definitely say no.

-one
Mar 30 '10 at 2:01
source share



All Articles