【问题标题】:Alternatives to Conditional Compilation in C#C# 中条件编译的替代方案
【发布时间】:2026-02-20 09:35:02
【问题描述】:

在 C# 中使用条件编译代码的替代方法是什么?

我有一个类有很多基于 #ifdef .. 的代码。一段时间后我的代码无法阅读。

寻找重构技术以提高代码的可读性和维护与许多#if defs

【问题讨论】:

  • 为什么首先需要它?是关于调试信息吗?

标签: c# conditional-compilation


【解决方案1】:

一件事是使用ConditionalAttribute

[Conditional("DEBUG")]
public void Foo()
{
    // Stuff
}

// This call will only be compiled into the code if the DEBUG symbol is defined
Foo();

它仍然是条件编译,但基于属性而不是#ifdef,这使得它通常更简单。

另一种选择是在执行时简单地使用布尔值,而不是在编译时全部使用。如果您能向我们提供更多关于您想要实现的目标以及您如何使用条件编译的详细信息,那将会很有用。

【讨论】:

  • 在将字符串作为参数的调试打印的情况下,尽管没有任何参数被评估,但这些字符串仍然可以被嵌入到程序的可执行文件中。你知道在 C# 中获得与 C++ 的“#define DebugPrint ((void)0)”相同结果的方法吗?
  • @Blake:你确认这是真的吗?我没想到会这样,虽然我可能错了。
【解决方案2】:

另一种方法是使用ConditionalAttribute。条件属性的工作方式类似。

#define TRACE_ON
using System;
using System.Diagnostics;

public class Trace 
{
    [Conditional("TRACE_ON")]
    public static void Msg(string msg)
    {
        Console.WriteLine(msg);
    }
}  

public class ProgramClass
{
    static void Main()
    {
        Trace.Msg("Now in Main...");
        Console.WriteLine("Done.");
    }
}

【讨论】:

    【解决方案3】:

    如果是代码可读性问题,您可以考虑使用 .Net 的部分类限定符并将条件代码放在单独的文件中,所以也许您可以有这样的东西...

    foo.cs:

    public partial class Foo
    {
        // Shared Behavior
    }
    

    foo.Debug.cs:

    #if DEBUG
    public partial class Foo
    {
        // debug Behavior
    }
    #endif
    

    foo.bar.cs:

    #define BAR
    #if BAR
    public partial class Foo
    {
        // special "BAR" Behavior
    }
    #endif
    

    我不确定您是否可以在代码文件之外定义条件,所以这样做可能会降低条件定义的灵活性(例如,您可能无法针对 BAR 创建条件分支例如,在主文件中,并且必须维护多个定义的 BAR 可能会变得丑陋),并且需要一定的勤奋才能进入文件以有效地启用/禁用那段代码。

    所以,使用这种方法最终可能会带来比它解决的更多的复杂问题,但是,根据您的代码,它可能会有所帮助吗?

    【讨论】:

      【解决方案4】:

      使用ConditionalAttribute 将是一个开始。否则,人们经常对条件编译所做的很多事情通常可以通过控制反转和/或明智地使用工厂来处理。

      【讨论】:

        【解决方案5】:

        多态性。

        处理它的方式与处理任何在相同条件下具有大量条件分支的意大利面条代码相同。

        将差异抽象为基类或接口。

        根据构建(一个#if)构建具体类。将具体对象传递给您的 App,然后您的 App 调用接口上定义的方法。

        【讨论】:

          【解决方案6】:

          如果您使用条件编译的原因可以轻松重构,您可以考虑使用Managed Extensibility Framework 在运行时根据条件动态加载代码。

          【讨论】:

            【解决方案7】:

            扩展 Jon 的答案,虽然使用 ConditionalAttribute 有许多限制,但有一个显着优势。当条件为假时,将省略对条件方法的调用。例如,您可以向日志系统添加 100 次调用,例如用于调试,这些调用可以有条件地从生产代码中排除。当它们被排除时,调用不需要调用的方法不会产生任何开销。使用#ifdef,您必须包装对日志系统的每次调用以有条件地排除它们。

            请注意,如果条件方法的调用者被重新编译,这仅适用于程序集。

            【讨论】: