Search code examples
c#switch-statementcoding-stylecommand-line-argumentsgoto

How to reuse switch block labels without goto?


How to implement the following code without goto and unnecessary code complexity?

namespace Test
{
    static class Program
    {
        bool keyA = false;
        bool keyB = false;
        // ...
        static void Main(string[] args)
        {
            foreach (string arg in args)
            {
                switch (arg.ToLowerInvariant())
                {
                    case "-a":
                        if(keyA) break;
                        keyA = true;
                        // do here also what the A key requires
                        break;
                    case "-b":
                        if(keyB) break;
                        keyB = true;
                        // do here also what the B key requires
                        goto case "-a"; // key B includes the action of key A
                    // ...
                }
            }
        }
    }
}

The only thing that suggests itself is to duplicate the lines of code from key A to key B or use stuffing everything into methods, but this doesn’t look convenient and compact to view.


Solution

  • I came up with a solution to my question: using local functions. This allowed me to avoid significant code refactoring and goto usage. One of the main advantages of local functions is that they have access to variables created in the method where they are defined. Unlike regular functions, local functions can “see” these variables. At the same time, the code remains close to the original.

    namespace Test
    {
        static class Program
        {
            static bool keyA = false;
            static bool keyB = false;
            // ...
            static void Main(string[] args)
            {
                int someOption = 0;
                foreach (string arg in args)
                {
                    switch (arg.ToLowerInvariant())
                    {
                        case "-a":
                            void KeyA()
                            {
                                if (keyA) return;
                                keyA = true;
                                someOption = 1; // so it's possible
                                // do here also what the A key requires
                            }
                            KeyA();
                        break;
                        case "-b":
                            if (keyB) break;
                            keyB = true;
                            // do here also what the B key requires
                            KeyA(); // key B includes the action of key A
                        break;
                        // ...
                    }
                }
            }
        }
    }