【问题标题】:Can I have global preprocessor definitions in C# library?我可以在 C# 库中有全局预处理器定义吗?
【发布时间】:2012-02-21 15:08:16
【问题描述】:

在 C# 中,您可以使用类似于 C/C++ 语法的宏进行条件编译。这将使以下情况发生:

#define MYMACRO
....
#if MYMACRO
//some C# code logic 
#else
//some other C# code logic

我需要在 C# 库项目的专用文件中定义一些宏,并且一旦定义,我需要这些宏在整个库中可见。问题是上面的代码只适用于单个文件。

我知道解决此问题的另一种方法是将宏添加到构建命令中。这将负责为整个.dll 定义宏,并且我将使#if - #else 检查在库中我想要的任何位置工作。这种方法的问题是我希望能够轻松地维护宏。将它们放在项目内的文件中将是完美的。我也想在里面放一些 cmets,这样我就会知道每个宏在做什么。如果我必须将宏作为构建参数传递,这将不适用。另一个原因是能够通过简单地评论和检查行为来打开/关闭宏。

有没有一种体面的方法来满足我的要求?我不想处理任何构建自动化工具,例如MSBuildNAnt 或类似的东西,如果没有其他方法,我会很感激您认为哪个是更好的选择。

【问题讨论】:

  • 您可以将定义添加到 csproj 文件中......
  • 你的意思是,作为构建参数?如果这是您的想法,我已经提到我现在对这种方法不满意。如果没有,我会很高兴你能分享更多关于如何做到这一点的信息。谢谢
  • 在这种情况下,我认为在不同的类中有不同的实现并基于配置文件(使用 IoC 容器)注入它们会更好,这对于不同的环境可能会有所不同。并且在应用程序启动时进行一次运行时检查不会影响性能。
  • @svick,这是一个很好的解决方案,但我担心在我的情况下这是我想避免的。 DI 意味着库的使用者应该了解环境依赖关系并且应该注意正确的注入——这使得库不是一个独立的库并且具有更严格的要求。我追求的主要目的之一是使消费者代码不复杂,或不依赖于这些“内部”考虑因素。
  • 你可以使用Poor Man's DI,或者编译一个轻量级容器作为你项目的一部分。 Here's one example. 这不是我的首选解决方案,但它是一种选择。

标签: c# .net c-preprocessor


【解决方案1】:

使用图形界面

  1. 在 Visual Studio 中打开项目
  2. 在解决方案资源管理器中右键单击项目文件转到属性
  3. 转到Build tab 并确保在配置下拉菜单中选择All Configurations
  4. 确保在Platform 下拉菜单中选择了All Platforms
  5. Conditional Compilation Symbols 文本框中键入您想要的Preprocessor Definitions,用分号分隔

到项目文件

  1. 在文本编辑器中打开项目文件
  2. 将此代码复制并粘贴到现有PropertyGroup 的末尾

    <PropertyGroup Condition="'$(VariableName)'=='VarableValue'"> <DefineConstants>PDEF1;PDEF2;PDEF3</DefineConstants> </PropertyGroup>

  3. 如果不需要添加条件,请删除Condition="'$(VariableName)'=='VarableValue'"部分

  4. 保存项目文件并从 Visual Studio 打开

发件人:https://codeketchup.blogspot.sg/2018/04/how-to-add-project-level-preprocessor.html

【讨论】:

    【解决方案2】:

    我还建议按照@Hans Passant 的建议将宏放入项目设置(csproj 文件)中。

    如果您需要记录定义,您可以在解决方案中添加一个说明设置含义的文档文件。

    如果没有太多变体,您可以为每个变体定义一个新的项目配置。这将允许您为每个变体预先配置必要的#defines 列表,然后只需从工具栏中的配置组合框在它们之间切换。如果您想暂时禁用一个选项,您可以复制当前配置并删除#define,然后在您测试后删除该配置。

    我可以建议使其“更简单”的下一个选项(按照您的建议将设置和文档组合到一个文件中)是使用简单的文本文件(设置 + cmets)来配置项目,并花 15 分钟编写一个快速的 c# 应用程序来读取此文件并将其包含的设置写入 .csproj 文件 - 它只是 XML,所以应该是一个简单的应用程序来编写。您可以轻松地调整此文件并运行您的更新程序应用程序来更改项目设置。如果这是您经常做的事情,请花 30 分钟的时间在上面添加一个带有复选框的 UI,以便更轻松地选择设置。

    不过,您所描述的概念听起来很奇怪。库的要点通常是您拥有一个可以由许多客户端共享的标准化代码块,因此更改这些类型的定义以重新配置整个库并不是我希望经常做的事情.也许您有充分的理由,但可能值得回顾一下为什么您需要解决这个#define 问题。

    (例如,如果您有很多客户需要“库”的不同变体,最好的方法是使用配置(如上所述)来允许您在批处理构建中构建所有需要的变体。如果您只是尝试许多不同的算法/技术然后你可以重新设计库的块,这样你就可以将大多数#defines 的影响限制在单个 .cs 文件中,这样它们就不再需要是全局的了?也许库不应该在单个 dll 中,或者需要一个插件架构来允许您选择库中包含的“模块”)

    【讨论】:

    • 感谢这篇冗长但有用的帖子。我已经开始重新考虑使用预处理器指令的方法。我不想在我的库中以任何形式使用 DI,所以我会尝试对配置做一些事情。我想,您关于编写将获取文件并将其添加到 csproj 文件的应用程序的其他建议也可以作为预构建命令应用。
    【解决方案3】:

    C#“预处理器”指令的工作方式与 C 预处理器指令不同。对您来说最重要的区别是没有 #include 的等价物。正常情况下不需要它,因为 C# 没有(或不需要)头文件。我不认为你想要什么是可能的,除非你以某种方式创建自己的预处理器或使用#defines 读取文件并将它们变成msbuild的参数。

    但我认为使用更多面向对象的方法会更容易:将不同的方法封装到类中并使用它们。要指定使用哪一个,您可以使用依赖注入。这意味着您必须随库一起提供 DI 库,但我认为这是值得付出的代价。

    此外,这种方法可以缓解条件编译的问题:指定不同的符号集可能会以意想不到的方式破坏构建。

    【讨论】:

      【解决方案4】:

      您可以使用“项目 + 属性”、“构建”选项卡、“条件编译符号”设置为整个项目#define 它们。这会在项目文件中设置&lt;DefineConstants&gt; 元素。您可以使用 msbuild 覆盖此属性,方法是为其提供 /property:DefineConstants="MYMACRO" 命令行选项。

      【讨论】:

      • 感谢您提供此信息,但这不是我所需要的完全。我需要在标准 C# 文件中定义的宏,但要达到与您提到的相同的效果。我开始相信 VS 的标准功能可能无法实现。
      • 对,如果您的首选方法可行,我不会发布此答案。
      • 这个答案对我有帮助,而不是其他答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-01
      • 2015-07-12
      • 2011-04-02
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多