#if DEBUG 与条件条件(“DEBUG”)

发布于 2024-09-25 06:25:11 字数 248 浏览 8 评论 0原文

在大型项目中哪个更好用,以及为什么:

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

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

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)
{ ... }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

り繁华旳梦境 2024-10-02 06:25:11

这实际上取决于您的目的:

  • #if DEBUG:此处的代码在发布时甚至不会达到 IL。
  • [Conditional("DEBUG")]:此代码将到达 IL,但是除非在编译调用方时设置了 DEBUG,否则对该方法的调用将被省略。

就我个人而言,我根据情况使用两者:

Conditional("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 是在调用程序集中定义的。

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.

与之呼应 2024-10-02 06:25:11

嗯,值得注意的是,它们根本不是同一件事。

如果未定义 DEBUG 符号,则在第一种情况下,SetPrivateValue 本身不会被调用...而在第二种情况下,它将存在,但任何调用者 在没有 DEBUG 符号的情况下进行编译的人将省略这些调用。

如果代码及其所有调用者位于同一个程序集中,则这种差异不太重要 - 但这意味着在第一种情况下,您需要有#if也围绕调用代码进行调试。

就我个人而言,我推荐第二种方法 - 但您确实需要在头脑中清楚地了解它们之间的区别。

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.

平安喜乐 2024-10-02 06:25:11

我确信很多人会不同意我的观点,但是作为一名构建人员,我经常听到“但它可以在我的机器上运行!”,我认为你几乎不应该使用任何一个。如果您确实需要进行测试和调试,请找出一种方法使可测试性与实际的生产代码分开。

在单元测试中通过模拟抽象场景,为您想要测试的一次性场景制作一次性版本,但不要将调试测试放入您为生产版本测试和编写的二进制文件的代码中。这些调试测试只是向开发人员隐藏了可能的错误,因此直到流程后期才发现它们。

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.

°如果伤别离去 2024-10-02 06:25:11

这个也很有用:

if (Debugger.IsAttached)
{
...
}

This one can be useful as well:

if (Debugger.IsAttached)
{
...
}
む无字情书 2024-10-02 06:25:11

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

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

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

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

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

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
}
紫轩蝶泪 2024-10-02 06:25:11

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

假设 #if DEBUGConditional 函数存在于主项目可执行文件引用的 DLL 中。使用#if,将根据库的编译设置执行条件评估。使用 Conditional 属性,将根据调用者的编译设置执行条件评估。

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.

最佳男配角 2024-10-02 06:25:11

我有一个 SOAP WebService 扩展,可以使用自定义 [TraceExtension] 记录网络流量。我仅将其用于调试构建,并在发布构建中省略。使用#if DEBUG 包装[TraceExtension] 属性,从而将其从Release 版本中删除。

#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(...)

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(...)
醉生梦死 2024-10-02 06:25:11

通常,您会在 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        
}

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        
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文