As I understand statements like Debug.WriteLine() will not stay in the code in the Release build. On the other hand Trace.WriteLine() will stay in the code in the Release build.
What is controling this behaviour? Does the C# compiler ignores everything from the System.Diagnostics.Debug class when the DEBUG is defined?
I am just trying to understand the internals of C# and just curious.
These methods use the ConditionalAttribute to designate when they should be included.
When DEBUG is specified as a #define, via the command line or the system environment (set DEBUG = 1 in the shell), a method marked with [Conditional("DEBUG")] will be included by the compiler. When DEBUG is not included, those methods and any calls to them will be omitted. You can use this mechanism yourself to include methods under certain circumstances and it is also used to control the Trace calls like Trace.WriteLine (this uses the TRACE define).
This is due to ConditionalAttribute; the compiler ignores calls to methods marked as conditional unless that symbol is defined.
You can have your own:
[Conditional("BLUE")]
void Bar() {...}
which will only be called when BLUE is defined.
Note that there are some restrictions, to make "definite assignment" work:
no return value
no out parameters
(the same restrictions apply to partial methods for similar reasons)
Related
I'm making a managed .NET debugger using MDBG sample.
Currently I'm struggling with StepInto behavior, while StepOut and StepOver seems to work.
To achieve Just-My-Code stepping I'm calling SetJMCStatus on modules load. That works fine and allow me to debug just my code.
But since I'm setting entire module as JMC, some auto-generated code comes into play and ruin stepping-into. An example of such code could be auto-property.
Since debugger is executing Il instructions, with step-into I'm getting inside auto-generated get_propertyName and set_propertyName method, which are marked as my code, because they are part of my module.
To distinguish such auto-generated code from my code I can use presence of debugging symbols, that are missing in case of auto-generated code. And then I could simply mark method as not my code to skip it during stepping.
The problem is I don't know which methods are auto-generated before I'm getting inside during stepping. When I stepped inside a method that has no debugging symbols I can mark it as not my code, but it's too late - debugger stopped where it supposed not to stop.
Theoretically I could iterate over my module methods using IMetadataImport and set their JMCStatus when debugger starts, but it seems quite expensive:
foreach (var methodToken in mdbgModule.Importer.EnumerateAllMethodTokens()) {
var func = mdbgModule.GetFunction(methodToken);
if (func.SymMethod == null)
func.CorFunction.JMCStatus = false;
}
If only I would know what function is going to be executed next, then I would be able to set it's status and prevent stepping inside auto-generated code for the first time.
I'm sticking with MDBG approach for stepping, not changing anything, just calling SetJMCStatus where it's needed, so I'm not sure if it makes sense to provide any code... If so, I'll edit the question, just add a comment!
Any suggestion on topic is greatly appreciated!
Regards,
Mike Stall hinted at one option, you could set JMC for the entire module and then when the debugger stepper breaks, check to see if the method is debuggable, if not then disable it's JMC status and rerun the stepper. (I'm not sure if this will result in a change in behaviour if the resuming stepper would need to step out before stepping in again.)
You could probably improve things by only setting JMC for modules that have a pdb available and by disabling JMC for classes/methods with [DebuggerNonUserCode] applied (and perhaps [DebuggerHidden] too). But rather than enumerating all the classes/methods and checking if they have the attribute, enumerate the custom attributes and work back (IMetaDataImport::EnumCustomAttributes with tkType set but not tk, then use IMetaDataImport::GetCustomAttributeProps to get the thing its applied to).
You might be able to do something similar with the [CompilerGenerated] attribute if its applied at the method level, but will get false positives when applied at the class level (the compiler applies it to state machines for iterators and async methods, but both will likely have non-generated code too).
I have a C# program where some parts of code are generated using D-style mixins (i.e., the body of the method is compiled, executed, and results inserted into a class). The method is marked with [MixinAttribute] and, naturally, I don't want it to be compiled into the program. Is there some cheap way of preventing the method decorated with this attribute from being included in a build?
The only way is with compiler conditionals:
#if DEBUG
[MixinAttribute]
// method you don't want included
#endif
The problem with this approach is that you then create a member which will be unavailable in builds where DEBUG is not defined. You then have to mark all usages with the conditional, and I don't think this is what you want. It's not quite clear but I think what you are really asking is how you create dynamic call sites at build time, or, rather, at JIT time (which is what the ConditionalAttribute controls). If this is the case, you can't really do this easily in C# without using some kind of dynamic dispatch overriding (using some proxying library) or by using some post-processing tool like PostSharp to manipulate the compiler output.
I have this simple code :
void Application_BeginRequest(object sender, EventArgs e)
{
Trace.Write("Exception Handling", "......");
}
However re-sharper scream (no-error only suggest) about :
Method invocation is skipped. Compiler will not generate method
invocation because the method is conditional, or it is a partial
method without implementation
I'm not able to see this line in the Trace output.
however - other traces - I do see.
Why is that ?
(p.s. The page (which is under web Site project) has trace="true").
Be sure that the TRACE constant is defined in your project settings for your current build configuration.
UPDATE
Since it's a website project, you could put
#define TRACE
at the top of Global.asax.cs so that the trace symbol is defined.
To quote the JetBrains wiki (which may* be linked to from the ReSharper menu under 'Why is ReSharper suggesting this'):
While coding, you may encounter warnings regarding methods whose
invocations will not be generated by the compiler. Why would that be?
Typical cases are conditional methods that will not be compiled (e.g.,
it’s marked with [ReSharperInt:Conditional("DEBUG")] and you’re in
RELEASE mode). Another reason why a method may be skipped is that,
at some point, its body has been declared as partial and the
implementation wasn’t provided.
Given that this is on a method of Trace, I'd suggest the first of these typical cases is the one that applies.
* I haven't got v7 yet
When Debug.Assert() method calls exist in source code and I compile in release mode, does the compiler generate the IL for the Debug.Assert() even though it's not called?
One of our developers added an Assert recently that displays information about our internal security. Could someone look at the release mode IL and figure out the text for the assert?
No, the members of the Debug class (with the ConditionalAttribute attribute) do not emit IL. There is no explicit mention on MSDN, however the following two quotes imply the behaviour quite well, so to augment Roy's answer:
If you use methods in the Debug class to print debugging information
and check your logic with assertions, you can make your code more
robust without affecting the performance and code size of your
shipping product.
So, no size difference implies no output from these whatsoever, and
The ConditionalAttribute attribute is applied to the methods of Debug.
Compilers that support ConditionalAttribute ignore calls to these
methods unless "DEBUG" is defined as a conditional compilation symbol.
Refer to a compiler's documentation to determine whether
ConditionalAttribute is supported and the syntax for defining a
conditional compilation symbol.
Which means that, at the compiler level, these calls won't even be considered (when DEBUG is not defined.)
It does not by default, unless you define the DEBUG symbol (and by default, for Release that is turned off).
To verify, open your Project Properties and select the Build pane in Visual Studio. It will show the checkbox "Define DEBUG constant". If it is turned on for Release, then asserts will fire; otherwise, they won't.
Is there a way to output a warning in the debugger if a certain method is used in the code? I have a couple of delicate methods that should only be used in exceptional cases, so I'd like to have some kind of warning output if they are actually called anywhere in the project.
Is this possible?
You should consider using the Obsolete attribute. It allows you to mark a method which should not be used. It takes two optional parameters a message and a flag indicating if the complier should fail or raise a warning.
You can use the Debugger.WriteLine method to see messages in the Debugger
Debugger.WriteLine("Don't use this method");
This is easily missed or ignored though. A more aggressive way of preventing this may be an assert.
Debugger.Fail("Are you sure you want to use this method?");
Yet another way to achieve this would be to mark the method as deprecated. This will result in a warning at compile time vs. debug time. You mentioned there are several places where it can be validly used. In those cases you could suppresse the deprecation warning with a pragma. This means only new uses of the method would cause a compile time warning which sounds like what you're after.