C# 使用编译器指令支持多个平台

C# 使用编译器指令支持多个平台,c#,software-design,compiler-directives,C#,Software Design,Compiler Directives,这是一个通用的软件设计问题 使用#if编译器指令支持多个平台是一个好主意吗。例如,我有三个文件: IScreen.cs public interface IScreen { ... } ScreenWin.cs #if WIN public class Screen : IScreen { ... } #endif ScreenMac.cs #if WIN public class Screen : IScreen { ... } #endif 这似乎很酷,因为我可

这是一个通用的软件设计问题

使用#if编译器指令支持多个平台是一个好主意吗。例如,我有三个文件:

IScreen.cs

public interface IScreen {
   ...
}
ScreenWin.cs

#if WIN

public class Screen : IScreen {
  ...
}

#endif
ScreenMac.cs

#if WIN

public class Screen : IScreen {
   ...
}

#endif
这似乎很酷,因为我可以使用BDD,并拥有如下功能:

Given a Screen exists with width: 1920 and height: 1080
并且将根据编译器指令使用正确的屏幕

这似乎也比尝试使用抽象工厂获得更好的性能


缺点是什么?

缺点包括必须编译多个二进制文件-每个平台一个

如果不小心,您可能会在代码的许多部分使用预处理器指令将代码弄乱。请参阅有关反转这样一个代码库的问题


如果可以在代码中检测平台,这是一种更好的方法。

正如@Oded所回答的,使用编译时directoves的缺点是必须为每个平台编译特定的二进制文件。好的一面是,你没有一个臃肿的一刀切的应用程序,它在每个平台上都更大、更慢,仅仅因为它是平台独立的

另一个下侧是如果很多VisualStudio工具只考虑“当前活动”代码。例如,intellisense和重构工具—如果您希望将IScreen重命名为IDisplay,那么您会发现重构工作正常,所有PC代码都得到了完美更新,但所有Mac代码都会严重损坏,因为重构工具根本看不到其他代码分支。类似地,很容易在PC分支上更改代码,而忘记对Mac分支进行相应的更改,从而再次破坏它

工厂而不是“#if”的好处是,单个二进制映像可能可以在每个平台上运行,并且在创建具体实现时只需检查主机平台一次(因此在运行时仍然非常有效,但会更大,因为您必须在一个发行版中发布所有平台变体)


然而,通过使用更模块化的设计模式而不是#如果:将卫星组件用于特定于平台的实现,则可以实现两个方面的最佳效果。在这种方法中,主应用程序代码将指定
IScreen
接口,然后在ScreenImplementation.dll程序集的不同平台特定变体中有具体的
Screen
(Mac)和
Screen
(PC)类。您还可以发布一个覆盖所有平台的安装程序(只需为主机平台部署适当的卫星dll)。这使得使用#if的效率/大小得到了边际的提高,但实际上不必用条件来打乱代码。(当然,这种模块化方法对#if和工厂设计都有意义——一旦将特定于平台的实现拆分为单独的程序集,它们就更像是一种部署选项,而不是核心实现体系结构)

管理编译器指令的可伸缩性非常差。我也是,谢谢你的回答。嗯。这个指令链接看起来很糟糕。我已经远离指令很久了。我第一次考虑使用它们,我会考虑单个二进制的优点。重构问题是一个很大的缺点。谢谢你指出这一点。二进制膨胀可能是个问题。我首先考虑这种方法的唯一原因是我们对所有编码都使用BDD。例如,我们可以在Mac上实现屏幕。签入Git。在Windows环境中签出,测试将失败。在windows上实现这些场景,现在两个系统的行为都相同了。在这两种环境中工作的团队也会很快发现系统行为的任何变化。谢谢你的回复。