在大型项目中,使用哪种方法更好,以及为什么:

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

or

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

当前回答

这取决于你想要什么:

#if DEBUG:这里的代码在发布时甚至不会到达IL。 [条件返回("DEBUG")]:此代码将到达IL,但是对方法的调用将被省略,除非在编译调用方时设置了DEBUG。

就我个人而言,我会根据情况使用这两种方法:

有条件的(“DEBUG”)例子:我使用这个,这样我就不必在发布期间回头编辑我的代码,但在调试期间,我想确保我没有任何拼写错误。当我试图在INotifyPropertyChanged中使用属性名时,这个函数检查我是否正确地键入了属性名。

[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));
}

你真的不想使用#if DEBUG来创建一个函数,除非你愿意用相同的#if DEBUG来包装对该函数的每个调用:

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

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

对比:

[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示例:我在尝试为WCF通信设置不同的绑定时使用这个。

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

在第一个示例中,所有代码都存在,但除非打开DEBUG,否则将被忽略。在第二个例子中,const ENDPOINT被设置为"Localhost"或"BasicHttpBinding",这取决于是否设置DEBUG。


更新:我正在更新这个答案,以澄清一个重要而棘手的问题。如果选择使用ConditionalAttribute,请记住在编译期间省略调用,而不是运行时。那就是:

MyLibrary.dll

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

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

当按照发布模式编译库时(即没有DEBUG符号),它将永远省略从A()中调用B(),即使包含了对A()的调用,因为在调用程序集中定义了DEBUG。

其他回答

通常你会在Program.cs中需要它,在这里你想要决定在非调试代码上运行调试,而在Windows服务中也是如此。因此,我创建了一个只读字段IsDebugMode,并在静态构造函数中设置其值,如下所示。

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        
}

这取决于你想要什么:

#if DEBUG:这里的代码在发布时甚至不会到达IL。 [条件返回("DEBUG")]:此代码将到达IL,但是对方法的调用将被省略,除非在编译调用方时设置了DEBUG。

就我个人而言,我会根据情况使用这两种方法:

有条件的(“DEBUG”)例子:我使用这个,这样我就不必在发布期间回头编辑我的代码,但在调试期间,我想确保我没有任何拼写错误。当我试图在INotifyPropertyChanged中使用属性名时,这个函数检查我是否正确地键入了属性名。

[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));
}

你真的不想使用#if DEBUG来创建一个函数,除非你愿意用相同的#if DEBUG来包装对该函数的每个调用:

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

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

对比:

[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示例:我在尝试为WCF通信设置不同的绑定时使用这个。

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

在第一个示例中,所有代码都存在,但除非打开DEBUG,否则将被忽略。在第二个例子中,const ENDPOINT被设置为"Localhost"或"BasicHttpBinding",这取决于是否设置DEBUG。


更新:我正在更新这个答案,以澄清一个重要而棘手的问题。如果选择使用ConditionalAttribute,请记住在编译期间省略调用,而不是运行时。那就是:

MyLibrary.dll

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

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

当按照发布模式编译库时(即没有DEBUG符号),它将永远省略从A()中调用B(),即使包含了对A()的调用,因为在调用程序集中定义了DEBUG。

这个也很有用:

if (Debugger.IsAttached)
{
...
}

让我们假设您的代码也有一个#else语句,它定义了一个空存根函数,处理Jon Skeet的一个点。这两者之间还有第二个重要的区别。

假设#if DEBUG或Conditional函数存在于被你的主项目可执行文件引用的DLL中。使用#if,将根据库的编译设置执行条件的求值。使用Conditional属性,条件的计算将根据调用程序的编译设置执行。

对于第一个示例,如果没有定义DEBUG,则SetPrivateValue将不存在于构建中;对于第二个示例,如果没有定义DEBUG,则对SetPrivateValue的调用将不存在于构建中。

对于第一个示例,您还必须使用#if DEBUG包装任何对SetPrivateValue的调用。

对于第二个示例,将省略对SetPrivateValue的调用,但请注意,SetPrivateValue本身仍将被编译。如果您正在构建一个库,那么引用您的库的应用程序仍然可以使用您的函数(如果条件满足),那么这很有用。

如果你想忽略调用并节省被调用者的空间,你可以结合使用这两种技术:

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