-4

Usually when I make console applications I start with something like this:

using System;

namespace ColorOptProblemTest
{
    class Program
    {
        const string HELP_TEXT = "";
        static ConsoleColor Default = Console.ForegroundColor;

        static void ShowHelp()
        {
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine(HELP_TEXT);
            Console.ForegroundColor = Default;
            Environment.Exit(0);
        }

        static void ThrowError(string Message)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("ERROR: " + Message);
            ShowHelp();
        }

        static void ManageArgs(string[] args)
        {
            switch (args.Length)
            {
                case 0:
                    ThrowError("At least one argument is required.");
                    break;
            }
        }

        static void Main(string[] args)
        {
            ManageArgs(args);
        }
    }
}

The important part is that I save Console.ForegroundColor for later when the program exits, so that the terminal can return to its original color.

Without compiler optimization, the code does everything like it's supposed to and works like a charm. With optimization, when the program exits, the color of the terminal is red.

Could it be, that this is some sort of bug in the optimizer? Maybe I'm just missing something elementary.

Nik Tedig
  • 453
  • 2
  • 6
  • 2
    I fail to see where you save and load the forecolor. And what is this 'optimization' that you talk about? Are you meaning RELEASE vs DEBUG? – Steve Oct 18 '20 at 19:57
  • @Steve Within the Release property settings you can set whether you want to optimize or not. The saving is done at the start of the class where I set default to Console.ForegroundColor. The loading is done just before exiting. It all works without optimization, but with optimization it doesn't for some reason. – Nik Tedig Oct 18 '20 at 20:03
  • 2
    You are relying on indeterminate behavior for the initialization of the static field. See duplicate. If you want to use that field to save the value before you change it, you need to use a deterministic mechanism for initialization. – Peter Duniho Oct 18 '20 at 20:18
  • @PeterDuniho Thanks. Just so I understand correctly: Static fields will be initialized sometime before using them thanks to optimization. That's why, without optimization on, the program works fine. If I've understood correctly, this can be avoided by adding an empty constructor to the class. Then the fields will be initialized after calling the first method? Or do I need to explicitly call the constructor? As far as I can see, this lazy initialization is done for performance reasons, so that the variables only get initialized when you need them, correct? – Nik Tedig Oct 19 '20 at 16:56
  • 1
    Yes, an empty **static** constructor will be executed before any static member is accessed (including static methods), and when the static constructor is present, static field initialization is deterministically done before execution of the static constructor. You need not (and cannot) explicitly call the static constructor. – Peter Duniho Oct 19 '20 at 17:48

1 Answers1

0

You don't need to do this at all. Instead use Console.ResetColor() to reset the colours back to what they were at the start of the process.

Looking at your code though I think colors are the least of your problems. For example, you can't output an error message without printing the help text and your method ThrowError doesn't throw an error. It would be more aptly named PrintError. You also don't need to force exit at the end of printing help text, let the calling code control what happens next. There are many scenarios where this hard coded behaviour wouldn't be desired.

Ashigore
  • 4,618
  • 1
  • 19
  • 39
  • I don't see how any of this _answers_ the question. The first paragraph offers an alternative, but fails to actually _explain_ the behavior that the question is asking about. The second paragraph is entirely speculative; it ignores the fact that the code example is there as a [mcve] not necessarily real-world implementation of a command-line program, as well as the fact that _many_ implementers of command-line programs do in fact use `Environment.Exit()` to immediately terminate the program rather than returning control to the caller. It's a standard and completely acceptable idiom. – Peter Duniho Oct 18 '20 at 20:24
  • I've never heard of Console.ResetColor(). I'll try it out, thank you. – Nik Tedig Oct 19 '20 at 16:34