编译器构造 - 基于 C# 中的类库版本的条件编译
本文关键字:类库 版本 条件 编译 基于 编译器 | 更新日期: 2023-09-27 17:55:34
在经典 C 中,我可能有一个 1.0 版本的库,它在其.h
文件中定义了一个常量,如下所示:
#define LIBRARY_API_VERSION_1_0
我可以在我的应用程序代码中做这样的事情:
#include "LibraryApi.h"
// ...
int success;
#ifdef LIBRARY_API_VERSION_1_0
int param = 42;
success = UseThisMethodSignature(42);
#endif
#ifdef LIBRARY_API_VERSION_2_0
float param = 42.0f;
success = UseOtherMethodSignature(param);
#endif
现在我正在使用 C#。因此,显然#define
的作用域仅限于定义它们的文件,因此我研究了此处描述的解决方案,即使用带有常量的静态类。但是,该解决方案要求在运行时进行检查,这引入了许多问题:
- 如果我一遍
- 又一遍地运行相同的代码检查额外的条件,则可能效率低下(尽管如果它是一个
const
,也许编译器或 .NET 运行时足够聪明以避免这种情况? - 您不能执行会引发编译器错误的操作。在上面的示例中,我用两种不同的类型定义了两次
param
。此外,UseOtherMethodSignature
可能不作为函数存在,如果两个块仅由if
/else
分隔,则不会编译。
那么,对于此类问题,可接受的解决方案是什么?我的情况是,我有多个版本的 Web 服务 API(根据你用它做什么,差异程度不同),我希望能够在不注释/取消注释一堆代码或其他一些同样愚蠢的手动过程的情况下进行编译。
编辑
就其价值而言,我更喜欢编译时解决方案 - 在我的场景中,我知道当我编译我将使用哪个版本时,我不需要弄清楚哪个版本的库在运行时在系统上可用。是的,这将起作用,但似乎矫枉过正。
我的目标是将其抽象到不同的包装库中。它们将是Visual Studio中的独立项目,并引用框架的不同版本。
// Shazaam contract.
public interface IShazaamInvoker {
Boolean Shazaam();
}
// ShazaamWrapper.v1.dll implementation
public class ShazaamInvoker : IShazaamInvoker {
public void Shazaam() {
Int32 param = 42;
return UseThisMethodSignature(param);
}
}
// ShazaamWrapper.v2.dll implementation
public class ShazaamInvoker : IShazaamInvoker {
public void Shazaam() {
Single param = 42f;
return UseOtherMethodSignature(param);
}
}
// Determine, at runtime, which wrapper to use.
var invoker = (IShazaamInvoker)(/*HereBeMagicResolving*/)
invoker.Shazaam();
我建议使用 DI 框架来加载适当的类/dll。如果可以重构代码以使用接口,则可以跨不同版本创建抽象层。有关可用的不同框架,请参阅此链接。
也许符合问题编译时性质的另一种解决方案是将生成的代码与 T4 一起使用
必须在项目级别定义编译符号。您可以在项目属性中执行此操作。这些符号可以使用 #if
指令引用。
您还可以创建包含一个或另一个编译符号的项目生成配置,还可以检查项目文件中的配置以包含基于符号的一个或另一个.dll引用,以便只需从工具栏的下拉列表中选择版本即可正确生成和调试两个版本。