0

I have a few methods that are called from within a few other methods. When in some of the methods a certain action is performed, I would like to go back to the very first method and skip the rest of the code. At the moment, I use booleans to check the "status" of the program but I would like to avoid this because the methods should be void since in essence they don't need to return anything. I found stuff like goto but that only works in the same method.

Question: is there a way to jump to a specific point in the code in a different method in C#? I found stuff on other languages but not a lot on C#.

Current situation:

    void test1()
    {
        bool status = test2();

        if (!status)
            return; // the other stuff will not get done

        Debug.WriteLine("Initialization OK");
    }

    bool test2()
    {
        bool status = test3();

        if (!status)
            return false; // the other stuff will not get done

        // do other stuff 
        return true;
    }

    bool test3()
    {
        if (xxx)
            return false; // the other stuff will not get done
        else
            // do other stuff 
            return true;
    }

Wanted situation:

    void test1()
    {
        test2();

        // do other stuff
        Debug.WriteLine("Initialization OK");

        GOTOHERE:
             Debug.WriteLine("Initialization NOT OK");
    }

    void test2()
    {
        test3();            
        // do other stuff 
    }

    void test3()
    {
        if (xxx)
            **GOTOHERE**; // Go directly to the location in test1() so that all unnecessary code is skipped

        // do other stuff
    }
10a
  • 429
  • 1
  • 5
  • 21
  • 4
    Returning something from your method to indicate what you should do afterwards is *exactly* what you should do. Thus return a boolean indicating if `test2` or `test3` succeeded and use that value to indicate if you want to proceed further. – MakePeaceGreatAgain Aug 09 '17 at 08:21
  • In this particular case, where you want to "jump" back when an error occurs, you might want to `throw` an exception and catch it in `test1()`. – C.Evenhuis Aug 09 '17 at 08:22
  • 2
    although it certainly depends on the situational conditions and individual needs, using `goto` is almost always a bad practice and can be replaced with alternative and friendly approaches. some further readings are https://stackoverflow.com/questions/11906056/goto-is-this-bad and http://www.drdobbs.com/jvm/programming-with-reason-why-is-goto-bad/228200966 – mcy Aug 09 '17 at 08:22
  • @C.Evenhuis No you don't! We really should try to get away from the mindset that exceptions are a good way to handle errors. Although there are **exceptions** to that rule, and that's where **Exceptions** should be used. – Noel Widmer Aug 09 '17 at 08:44
  • @NoelWidmer As far as I know exceptions aren't called exceptions because they are an exception to an "error rule", they're called exceptions because they fall outside the possible errors (part of) an application can recover from. I may have been too quick to assume, but it seems that this is what the OP is describing; he doesn't want `test2()` to be able to recover from the error that occurs in `test3()`. I don't know _what kind_ of error occurs here so I can't say if this would be a good idea or not. But I do agree that exceptions should not be used as a strange replacement for `goto`. – C.Evenhuis Aug 09 '17 at 11:30
  • 1
    @C.Evenhuis I do agree that if recovering is **not** important an Exception might be used. But I also almost always consider catching exceptions as a design flaw. Still, since the OP wants a specific behaviour (act on error) I wouldn't throw here. There are quite a couple young languages that allow you to panic (throw) but not to catch in order to prevent us from building logic on throwing and catching Exceptions. – Noel Widmer Aug 09 '17 at 11:40
  • In my case, whether or not a method needs to be completed, does not (solely) depend on errors but on the different outcomes of a 3D measurement. – 10a Aug 10 '17 at 07:18

7 Answers7

5

I was surprised to learn that C# does actually support a GOTO command. But it is designed to allow exit from deep nested loops.

This article explains it and gives lots of examples: https://www.dotnetperls.com/goto

However

Unless you are still coding in 1970 then using GOTO is considered very bad practice. It makes code maintenance very difficult. And it even causes problems and performance issues, and makes life for the JIT compiler more difficult.

The go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one's program.

Edsger W. Dijkstra

jason.kaisersmith
  • 8,712
  • 3
  • 29
  • 51
3

Returning something from your method to indicate what you should do afterwards is exactly what you should do. Thus return a boolean indicating if test2 or test3 succeeded and use that value to indicate if you want to proceed further. Don´t use goto nowadays as it only leeds to spaghetti-code, that is hard to maintain. To determine under which circumstances control-flow should jump to GOTOHERE you´d need to scan your entire code for that specific goto-statement.

In your case you want to indicate if some initialization-code works correct. Thus you can also throw an exception:

void test3()
{
    if (xxx)
        throw new Exception("Some text");

    // do other stuff
}

This way you don´t need to return anything from your method, but handle the exception appropriately:

void test1()
{
    try { test2(); }
    catch { 
        // some exception-handling such as logging
        return; 
    }

    Debug.WriteLine("Initialization OK");
}

This has the advantage that you don´t need to check in test2 if test3 succeeded, allowing you to let the exception bubble through your methods until it is finally handled by a catch. If no catch was found in the entire callstack your app will probably terminate.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Throwing exceptions is not really applicable since the completion of a method depends on different types of measurement results, not on an error. Or at least, that's not the problem I am looking to solve. – 10a Aug 10 '17 at 07:20
  • Then you should indicate what to the caller of your method should do based on the methods return-value as I mentioned above. Again: don´t jump around within your class making all your design having methods and properties quite obsolete. – MakePeaceGreatAgain Aug 10 '17 at 07:25
2

C# does have the goto keyword, which works just like in other languages. Declare a label as label_you_want_to_jump_to:, and use goto label_you_want_to_jump_to (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto).

Now that this is said, it is usually a bad idea to use goto, especially in such a way. Your problem might be solved more easily by refactoring a bit. Splitting test3 into two functions, reducing the amount of nesting might be such a way. You may also throw an exception in test3, and catch it in test1. It all depends on what you want to do.

pikzen
  • 1,413
  • 1
  • 10
  • 18
  • I only manage to use `goto` when it's used in the same method, not to jump to another method. – 10a Aug 09 '17 at 08:35
1

If you get rid of the explicit bools (which are redundant), your (rather contrived) example looks a lot "cleaner" in my opinion:

void test1()
{
    if (test2())
    {
        Debug.WriteLine("Initialization OK");
    }
}

bool test2()
{
    return test3();
}

bool test3()
{
    return xxx;
}

I also prefer to use positive rather than negative conditions, so "if (true)" rather than "if (!false)". This avoids double negatives, which are harder to understand.

Effectively we are using Predicate Logic. We can combine our predicates (methods than return bool without side effects) using the normal logic operators. Consider this example:

bool test4()
{
    if (test1())
    {
        if (test2())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

We note that this is simply a logical conjunction (and) of test1 and test2, so can simply use the && conjunction operator to make this much clearer:

bool test4()
{
    return test1() && test2();
}

Similarly for logical disjunction (or):

bool test5()
{
    if (test1())
    {
        return true;
    }
    else if (test2())
    {
        return true;
    }
    else 
    {
        return false;
    }
}

We can write this instead as:

bool test5()
{
    return test1() || test2();
}
Polyfun
  • 9,479
  • 4
  • 31
  • 39
0

I don't recommend it, but the simple answer to your question is to use a goto statement.

See: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto

You should, however, really be returning values from previous method calls that you can use to determine if you need to run other code.

You can also throw exceptions, but in general I'm not a fan of using them for control of flow unless the circumstance is exceptional (hence the name, I suppose). If you expect that control may flow this way or that, it is not exceptional.

Colin Mackay
  • 18,736
  • 7
  • 61
  • 88
0

I do understand your point but breaking the sequence of events (aka jumping) is not good practice. Your code becomes unreadable because the reader needs to jump from one place to another. There is a reason why you can't jump out of the current method:

What follows is a really simplified explanation. I am glosing over many details.
If you have knowledge about how the stack works you'll know that the runtime will push a new stack frame onto the stack for each new method invocation. That new stack frame contains the method's local variables as well as other things that are implementation details. If you want to jump to another method the runtime would need to push a new stack frame onto your stack in order to create those local variables for that method. So your goto would become a method invocation rather than a jump statement. Which is weird and not what you/we want. Use normal method invocations in such scenarios rather than jump statements.

There are widly accepted jumping statements like return, break and continue.
goto is not one of them, although I consider goto case to be a valid solution in some cases.

Returning the information about what to do next is the correct behaviour here.
I do agree that returning a bool is not very expressive from a sematic perspective, at least not whith your current method names. Naming improvement suggestion:

void DoTest1();
bool TryTest2();
bool TryTest3();
Noel Widmer
  • 4,444
  • 9
  • 45
  • 69
0

FYI

bool flag;

void test1()
{
    test2();

    if (flag) {
        // do other stuff
        Debug.WriteLine("Initialization OK");
    }
    else {
         Debug.WriteLine("Initialization NOT OK");
    }
}

void test2()
{
    test3();            
    if (flag) {
        // do other stuff 
    }
}

void test3()
{
    if (xxx)
        return;

    // do other stuff

    flag = true;
}
zuma
  • 26
  • 4