#line hidden vs. DebuggerNonUserCode attribute
I got this great question from the mailbag:
"[W]hat is the relation between the "# line hidden" directive and the DebuggerNonUserCode attribute ? Are these the same ?"
Short Answer:
They're both markings that library authors can put in their source code to mark certain portions as "hidden" to the end-user while debugging. In both cases, the debugger must detect them and do additional work to respect them. Visual Studio respects both of these. MDbg only respects #line hidden. #line marks lines within a function as hidden whereas the DebuggerNonUserCode marks entire functions as hidden.
More comparisons:
#line hidden | DebuggerNonUserCode | |
What does it affect? | single set of continuous lines within a function | entire function or class |
What does compiler do with it? (How could other languages besides C# use this) | Changes PDB mappings. Instructs the line to be mapped to 0xFeeFee, which serves as special value to debuggers to instruct it that that line is hidden. | Just a normal custom attribute, stored in the executable file. |
More info on MSDN : | wiki link | wiki link |
Example usage and more detail from my blog | here | here |
Dependency on CLR | None. Existed since .NET 1.0. | Depends on Just-My-Code (JMC), which was added in .Net 2.0 |
What could debugger do with it? | This is purely a contract between the compiler and the debugger communicated via the PDBs.If debugger stops at a line that maps to '#line hidden' it can elect to keep executing. It may elect to forbid breakpoints to be placed at hidden points. It stepping would normally stop at a hidden line, it may choose to continue stepping. | This requires the debugger to use JMC support from the CLR debugging services.Debugger must use Just-My-Code stepping and mark functions as non-user code. Debugger marks frames with the DebugNonUserCode attribute as non-user code. |
Note that since these are both enforced by the debugger, the debugger has to do extra work to make these features available to the end-user. But this also lets the debugger decide exactly what sort of policy it wants to expose. For example, the debugger can decide how to handle a breakpoint set in a function marked as DebuggerNonUserCode. (eg, Forbid it, warn the user, stop anyways, etc)