#if DEBUG vs. Conditional("DEBUG")

C#DebuggingPreprocessorDebug Symbols

C# Problem Overview


Which is better to use, and why, on a large project:

#if DEBUG
    public void SetPrivateValue(int value)
    { ... }
#endif

or

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }

C# Solutions


Solution 1 - C#

It really depends on what you're going for:

  • #if DEBUG: The code in here won't even reach the IL on release.
  • [Conditional("DEBUG")]: This code will reach the IL, however calls to the method will be omitted unless DEBUG is set when the caller is compiled.

Personally I use both depending on the situation:

Conditional("DEBUG") Example: I use this so that I don't have to go back and edit my code later during release, but during debugging I want to be sure I didn't make any typos. This function checks that I type a property name correctly when trying to use it in my INotifyPropertyChanged stuff.

[Conditional("DEBUG")]
[DebuggerStepThrough]
protected void VerifyPropertyName(String propertyName)
{
    if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        Debug.Fail(String.Format("Invalid property name. Type: {0}, Name: {1}",
            GetType(), propertyName));
}

You really don't want to create a function using #if DEBUG unless you are willing to wrap every call to that function with the same #if DEBUG:

#if DEBUG
    public void DoSomething() { }
#endif

    public void Foo()
    {
#if DEBUG
        DoSomething(); //This works, but looks FUGLY
#endif
    }

versus:

[Conditional("DEBUG")]
public void DoSomething() { }

public void Foo()
{
    DoSomething(); //Code compiles and is cleaner, DoSomething always
                   //exists, however this is only called during DEBUG.
}


#if DEBUG example: I use this when trying to setup different bindings for WCF communication.

#if DEBUG
		public const String ENDPOINT = "Localhost";
#else
		public const String ENDPOINT = "BasicHttpBinding";
#endif

In the first example, the code all exists, but is just ignored unless DEBUG is on. In the second example, the const ENDPOINT is set to "Localhost" or "BasicHttpBinding" depending on if DEBUG is set or not.


Update: I am updating this answer to clarify an important and tricky point. If you choose to use the ConditionalAttribute, keep in mind that calls are omitted during compilation, and not runtime. That is:

MyLibrary.dll

[Conditional("DEBUG")]
public void A()
{
    Console.WriteLine("A");
    B();
}

[Conditional("DEBUG")]
public void B()
{
    Console.WriteLine("B");
}

When the library is compiled against release mode (i.e. no DEBUG symbol), it will forever have the call to B() from within A() omitted, even if a call to A() is included because DEBUG is defined in the calling assembly.

Solution 2 - C#

Well, it's worth noting that they don't mean the same thing at all.

If the DEBUG symbol isn't defined, then in the first case the SetPrivateValue itself won't be called... whereas in the second case it will exist, but any callers who are compiled without the DEBUG symbol will have those calls omitted.

If the code and all its callers are in the same assembly this difference is less important - but it means that in the first case you also need to have #if DEBUG around the calling code as well.

Personally I'd recommend the second approach - but you do need to keep the difference between them clear in your head.

Solution 3 - C#

I'm sure plenty will disagree with me, but having spent time as a build guy constantly hearing "But it works on my machine!", I take the standpoint that you should pretty much never use either. If you really need something for testing and debugging, figure out a way to make that testability seperate from the actual production code.

Abstract the scenarios with mocking in unit tests, make one off versions of things for one off scenarios you want to test, but don't put tests for debug into the code for binaries which you test and write for production release. These debug tests just hide possible bugs from devs so they aren't found until later in the process.

Solution 4 - C#

This one can be useful as well:

if (Debugger.IsAttached)
{
...
}

Solution 5 - C#

With the first example, SetPrivateValue won't exist in the build if DEBUG is not defined, with the second example, calls to SetPrivateValue won't exist in the build if DEBUG is not defined.

With the first example, you'll have to wrap any calls to SetPrivateValue with #if DEBUG as well.

With the second example, the calls to SetPrivateValue will be omitted, but be aware that SetPrivateValue itself will still be compiled. This is useful if you're building a library, so an application referencing your library can still use your function (if the condition is met).

If you want to omit the calls and save the space of the callee, you could use a combination of the two techniques:

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
    #if DEBUG
    // method body here
    #endif
}

Solution 6 - C#

Let's presume your code also had an #else statement which defined a null stub function, addressing one of Jon Skeet's points. There's a second important distinction between the two.

Suppose the #if DEBUG or Conditional function exists in a DLL which is referenced by your main project executable. Using the #if, the evaluation of the conditional will be performed with regard to the library's compilation settings. Using the Conditional attribute, the evaluation of the conditional will be performed with regard to the compilation settings of the invoker.

Solution 7 - C#

I have a SOAP WebService extension to log network traffic using a custom [TraceExtension]. I use this only for Debug builds and omit from Release builds. Use the #if DEBUG to wrap the [TraceExtension] attribute thus removing it from Release builds.

#if DEBUG
[TraceExtension]
#endif
[System.Web.Service.Protocols.SoapDocumentMethodAttribute( ... )]
[ more attributes ...]
public DatabaseResponse[] GetDatabaseResponse( ...) 
{
    object[] results = this.Invoke("GetDatabaseResponse",new object[] {
          ... parmeters}};
}

#if DEBUG
[TraceExtension]
#endif
public System.IAsyncResult BeginGetDatabaseResponse(...)

#if DEBUG
[TraceExtension]
#endif
public DatabaseResponse[] EndGetDatabaseResponse(...)

Solution 8 - C#

Usually you would need it in Program.cs where you want to decide to run either Debug on Non-Debug code and that too mostly in Windows Services. So I created a readonly field IsDebugMode and set its value in static constructor as shown below.

static class Program
{

    #region Private variable
    static readonly bool IsDebugMode = false;
    #endregion Private variable

    #region Constrcutors
    static Program()
    {
 #if DEBUG
        IsDebugMode = true;
 #endif
    }
    #endregion

    #region Main

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main(string[] args)
    {

        if (IsDebugMode)
        {
            MyService myService = new MyService(args);
            myService.OnDebug();             
        }
        else
        {
            ServiceBase[] services = new ServiceBase[] { new MyService (args) };
            services.Run(args);
        }
    }

    #endregion Main        
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLucas BView Question on Stackoverflow
Solution 1 - C#myermianView Answer on Stackoverflow
Solution 2 - C#Jon SkeetView Answer on Stackoverflow
Solution 3 - C#Jimmy HoffaView Answer on Stackoverflow
Solution 4 - C#sofsntpView Answer on Stackoverflow
Solution 5 - C#P DaddyView Answer on Stackoverflow
Solution 6 - C#Kennet BelenkyView Answer on Stackoverflow
Solution 7 - C#Steven J. HathawayView Answer on Stackoverflow
Solution 8 - C#Yashwant ShuklaView Answer on Stackoverflow