Pergunta

This is a general software design question.

Is it a good idea to use the #if compiler directive to support multiple platforms. For example, I have three files:

IScreen.cs

public interface IScreen {
   ...
}

ScreenWin.cs

#if WIN

public class Screen : IScreen {
  ...
}

#endif

ScreenMac.cs

#if WIN

public class Screen : IScreen {
   ...
}

#endif

What seems cool about this is that I can use BDD and have something like:

Given a Screen exists with width: 1920 and height: 1080

and the correct Screen would be used based on the compiler directive.

This seems like you would also get better performance than trying to use an abstract factory.

What are some drawbacks?

Foi útil?

Solução

As @Oded has answered, the down-sode of using compile-time directoves is that you have to compile a specific binary for each platform. The up side is that you don't have a bloated one-size-fits-all application that is larger and slower on every platform just because it is platform-independent.

Another down-side of #if is that a lot of Visual Studio tools only consider the "currently active" code. For example, intellisense and refactoring tools - if you wished to rename IScreen into IDisplay, then you'd find refactoring worked and all your PC code was updated perfectly but all your Mac code would be badly broken as the refactoring tools simply wouldn't "see" the other code branch. Similarly, it's easy to make a change to the code on the PC branch and forget to make the corresponding change to the Mac branch, again breaking it.

The benefit of a factory instead of "#if" is that a single binary image can potentially be run on every platform, and you only need to check the host platform once when creating the concrete implementation (so it's still very efficient at runtime, but will be larger as you have to ship all the platform-variants within one distribution)

However, it is possible to get the best of both worlds by using a more modular design pattern instead of #if: use a satellite assembly for the platform-specific implementations. In this approach, the main application code will specify the IScreen interface, and then you would have Concrete Screen (Mac) and Screen (PC) classes in separate platform-specific variants of a ScreenImplementation.dll assembly. You can also ship a single installer that covers all platforms (by simply deploying the appropriate satellite dll for the host platform). This gives you the marginal efficiency/size improvements of using #if but withut actually having to mess up your code with conditionals. (Of course, this modular approach makes sense with both the #if and Factory designs - they become more of a deployment option rather than the core implementation architecture once you split the platform-specific implementations into separate assemblies)

Outras dicas

Drawbacks include having to compile multiple binaries - one per platform.

If not careful you may end up cluttering your code with preprocessor directive in many parts of your code. See this SO question about reversing one such codebase.

If you can detect platform within code, it is a better approach.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top