There's a good reason that methods on a "System.Diagnostics.Debugger" class are still compiled in retail builds, although this occasionally surprises folks. Here's why...
Background:
The System.Diagnostics.Debugger class provides some useful low-level debugging APIs such as:
(I previously blogged about the contrast between these managed APIs to their native counterparts)
These are implemented in mscorlib in the BCL. They exist in both debug and retail builds.
Here are some answers to common followup questions:
Question #1: Why aren't they just nops when a debugger is not attached?
Debugger.Log is indeed a nop if no debugger is attached. But the others still do things when a debugger isn't attached: Debugger.Launch and Debugger.IsAttached obviously innately make sense to exist when a debugger is not attached.
Debugger.Break() pops up a fatal error dialog. An alternative design would be for Debugger.Break() to indeed by a nop when no debugger is attached. However, this has some subtle issues:- If Debugger.Breaks() was a nop in retail builds, it would be easy to blindly sprinkle them throughout your app, but this could present significant noise when run under a debugger. (Imagine always stopping on every single 1st-chance exceptions). - It would violate the semantics that Debugger.Break() notifies the user. Under a debugger, it stops right at the line of interest. Outside the debugger, it presents an escalation dialog for Watson / Jit-debuggers, etc. This can be useful for implementing a retail assert.
Question #2: Why are S.D.Debugger methods in retail BCL builds?
We don't want different API public surface area across different flavors of system libraries. (the Condtional attribute helps avoid that problem) The only code in the process that needs to be debuggable is the code you're debugging. So debug applications may still link against retail libraries like mscorlib or other 3rd-party libraries. (They certainly uses retail versions of the runtime and the OS!)
Question #3: Why don't they have a Conditional attribute?
We don't use a conditional attribute on S.D.Debugger methdos because Conditional is a compiler-specific policy issue.
These are low-level primitives and try to be generally useful without enforcing a specific policy. Debug vs. Retail is a policy. And every time the platform picks the policy, it's wrong for some users.
You could write your own functions around them that enforce the particular policy that you want. For example, here are 2 different policies for wrapping the Break() function:
void MyBreak1() { if (Debugger.IsAttached) { Debugger.Break(); } } [Conditional(DEBUG)] void MyBreak2() { Debugger.Break(); }