10

While debugging I tried to save intermediate results of a calculation to a variable so that when a breakpoint condition is met I could check that value. However C# compiler (or CLR) optimized away that variable as unused. I solved the problem by making the variable a public field of the class, however I'd like to know if there is a straightforward solution to this problem.

"Optimize code" checkbox is unchecked. The build configuration is Debug.

Edit: Found that it only affects some unused variables in iterators that would normally end up as fields in the automatically generated iterator class; unused variables that are scoped within blocks not containing yield statements are retained.

srgstm
  • 3,649
  • 2
  • 24
  • 26
  • 1
    Do you have a specific scenario? Locals are *usually* retained in a debug build. Also: which compiler (exactly) are you using here? – Marc Gravell Oct 20 '11 at 06:33
  • The compiler is C# 4 (VS 2010, target framework 4.0), however I just did a few tests and can confirm that locals are retained in debug builds except in iterators which was my case. – srgstm Oct 20 '11 at 07:24
  • "iterators" was the key detail we were missing then... indeed they go through massive re-writing; I suspect adding something like the `WriteLine` is the best way to retain them through the munging process – Marc Gravell Oct 20 '11 at 07:30
  • Yes, but it is not possible to provide all the relevant details from the start because it is not usually clear which details are relevant. Your comments did point me in the right direction. – srgstm Oct 20 '11 at 07:51
  • 1
    For info, you aren't imagining it ;p http://i.stack.imgur.com/E73Uz.png – Marc Gravell Oct 20 '11 at 08:14
  • @MarkGravel Should it be considered a bug in C# compiler? I am aware that local variables in iterators usually end up as fields in the automatically generated iterator class. But I don't see any reason why the compiler cannot retain unused variables in iterators if optimizations are turned off. – srgstm Oct 20 '11 at 08:55
  • @MarkGravell I just noticed that not all unused variabled are optimized away. If you replace j = Fudge(i) in your code with while (i > 0) { int j = Fudge(i); i--; } the j variable will not be optimized away. – srgstm Oct 20 '11 at 10:31

5 Answers5

7

The lazy option would be.... use the value, ideally in a way that doesn't allow it to be held on the stack. For example:

 var tmp = SomeMethod();
 // your other code
 Debug.WriteLine(tmp);

the use of the value as an argument means it must be retained, but that line is automatically not compiled into release builds.

However! I must emphasize that locals are pretty-much always retained in an unoptimized/debug build, so I'm finding the scenario from the question hard to envisage.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

Handy utility:

using static _globals;

static class _globals
{
    [MethodImpl(MethodImplOptions.NoInlining), DebuggerHidden]
    public static void Nop<T>(out T x) => x = default(T);
};

class Program
{
    static void Main()
    {
        int i;     // unreferenced variable

        /// ...

        Nop(out i);

        /// ...
    }
};
Glenn Slayden
  • 17,543
  • 3
  • 114
  • 108
2

If you are using Visual Studio, why not just add a breakpoint on the line following the line on which the calculation is being made, and then you can simply hover over the calculation to see the result in the intellisense/tooltip popup? I also think that you can add the calculation to the "watch" screen and view the result that way as well.

This is usually how I view the results of things I am debugging. Alternatively, you could just use the temp variable you created in some simple way to avoid getting the warning.

For example:

Console.Write(tempVariable);
  • One disadvantage of `Console` here is that it will be retained in release builds if you forget to remove it. – Marc Gravell Oct 20 '11 at 06:51
  • I cannot set breakpoint earlier because the breakpoint is conditional and the condition is evaluated later in the code. – srgstm Oct 20 '11 at 07:35
  • @MarcGravell I agree, that's why I suggested the use of a breakpoint first off. I guess if he chooses to use the solution of actually using the temp variable, then your way (using Debug) is a much better option. –  Oct 20 '11 at 07:46
  • @srgstm I do not really understand why you are unable to set a breakpoint. Have you tried doing this? Maybe if you post a section of your code I could help out a little more.... –  Oct 20 '11 at 07:47
  • @giygas73 he isn't imagining it; the scenario (see comments) is an iterator block: http://i.stack.imgur.com/E73Uz.png – Marc Gravell Oct 20 '11 at 08:14
  • I'll try to explain. Suppose that was not a breakpoint but an exception that was thrown very rarely and unpredictably. When debugger breaks at the exception, I want to see some intermediate results that led to this exception. Setting a breakpoint earlier will do no good. – srgstm Oct 20 '11 at 08:14
  • @srgstm but as a debugging aid, you can `catch{ throw; }` and put a breakpoint on the `throw` (and remove after debugging). Better still: `catch { Debugger.Break(); throw; }` – Marc Gravell Oct 20 '11 at 08:31
1

In my case "Optimize code" option was unchecked, still I was facing this issue. I checked it, build project then unchecked it and buid project again. This fixed issue for me.

Abhijeet Nagre
  • 876
  • 1
  • 11
  • 21
1

You need uncheck options "Optimize code" in project options for Debug build.

Tadeusz
  • 6,453
  • 9
  • 40
  • 58