条件编译是一种编译器指令,它允许在编译过程中根据条件语句包含或忽略代码的不同部分。这种技术在跨平台开发中非常有用,因为它可以指定特定平台编译的代码部分。条件编译通过使用#if、#endif、#elif和#else指令来实现,这些指令为源文件的不同部分添加了条件。使用这些指令,可以保持单一的源文件,同时根据不同的条件编译不同的代码块。
例如,在C++中,可以使用条件编译来决定编译哪些代码:
#if CONDITION
// 某些代码
#else
// 其他代码
#endif
条件编译的值决定了哪个代码块被包含。条件符号可以是任何标识符或关键字,除了true或false。条件编译指令应该总是以一组指令的形式书写,包括一个#if指令,零个或多个#elif指令,零个或一个#else指令,以及一个#endif指令。在这些指令之间,需要编写条件代码。
如果希望某些代码只在特定条件下编译,可以定义一个条件,并使用普通的if-else语句。这在处理共享项目时非常有用。以下是一个C#的示例:
public int calculate(int input)
{
int result;
#if CONDITION
result = input + 10;
#else
result = input - 10;
#endif
return result;
}
条件的值将决定功能。如果设置了CONDITION,结果将是input + 10;如果没有设置CONDITION,结果将是input - 10。
条件编译的使用场景包括隔离特定平台的代码,这样可以根据需要在任何地方使用它。但是,如果正在处理一个大型项目,条件编译可能会使代码变得难以管理。条件编译不能在可移植类库中使用,因为当它被编译时,它只生成一个单一的二进制文件。
在通用应用中,可以使用条件编译编写针对不同平台的代码,例如Windows商店和Windows Phone。可以选择为不同的项目编译哪些代码,因为这两个项目被编译成不同的包。这是定义特定平台代码的最简单方法。例如,可以尝试共享Windows Phone和Windows商店应用的代码库,并根据正在编译的应用或平台,改变代码的行为。以下是一个示例:
首先,使用空白模板创建一个C#通用应用。解决方案包含三个项目:Windows商店应用、Windows Phone应用和一个共享项目。在解决方案中,首先注意到Windows商店和Windows Phone项目都有一个单独的起始页面,即主页。但是,需要共享这个页面,所以将其中一个拖到共享项目中,然后从其他两个项目中删除主页。这不会造成任何问题,因为它只是一个空白页面。
现在有一个通用的共享主页。
在共享项目的主页中,创建了一个简单的用户界面,只有一个按钮和一个事件处理程序,以及一个TextBlock,希望在按钮点击时显示“Windows商店”或“Windows Phone”。将通过按钮点击事件处理程序中的条件编译来实现这一点。
#if WINDOWS_APP
#elif WINDOWS_PHONE_APP
可以通过属性->构建->条件编译符号来查看这些条件。在这里,Windows属性中定义的条件编译符号是NETFX_CORE和WINDOWS_APP,而在Windows Phone属性中,是NETFX_CORE和WINDOWS_PHONE_APP。Windows 8有一个名为NETFX_CORE的编译器指令集。因此,这对于Windows 8项目总是设置的,并且在Windows商店和Windows Phone中都很常见。
即使可以在这里添加编译条件,比如"MY_COMPILATION_CONDITION",并在项目中使用它,但让使用默认的。这里的条件是,如果是Windows Phone应用,希望显示“Windows Phone”,否则希望显示“Windows商店”。因此,在事件处理程序中,将使用条件编译。
可以看到这里的一些代码是灰色的,这只是因为IntelliSense正在帮助进行条件编译。可以通过顶部的下拉菜单在Windows和Windows Phone之间切换。可以看到平台设置为Windows,所以与另一个平台相关的代码是灰色的。这是一个非常有用的功能,因为可以很容易地注意到哪些代码将针对特定平台编译。
右键单击Windows项目,然后选择“设置为启动项目”。现在,如果通过点击按钮运行Windows应用,会得到:
如果选择Windows Phone作为启动项目并运行项目,Windows Phone项目将运行,可以看到它显示的是Windows Phone而不是Windows商店。
如果在共享项目中使用TopAppBar,应用程序在Windows商店中可以完美运行,但在Windows Phone中会抛出异常,因为TopAppBar不适用于Windows Phone。
通过使用XAML条件编译来管理Windows和Windows Phone之间的XAML差异是一个好方法。XCC是一个预处理器,它为XAML文件添加了条件编译支持。可以通过安装一个小型NuGet包在项目中启用XCC。它支持Windows通用应用和Xamarin Forms项目。
将通过NuGet包管理器添加这个。将在解决方案级别进行此操作,因为需要将其添加到两个项目中。每当从共享项目引用任何库或包时,都需要将其添加到两个项目中。
打开解决方案上下文菜单,然后选择“管理解决方案的NuGet包”。搜索xcc并安装XAML条件编译NuGet包到两个项目中。
添加了nuget包之后,需要在Main页面中声明它,希望使用它。
xmlns:win="http://schemas.microsoft.com/winfx/2009/xaml/presentation"
xmlns:wp="http://schemas.microsoft.com/winfx/2009/xaml/presentation"
xmlns:local="using:YourNamespace"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d win wp">
xmlns:win和xmlns:wp属性定义了条件编译XML元素和属性的命名空间。xmlns:win用于希望代码仅编译为Windows商店应用时,xmlns:wp用于希望代码仅编译为Windows Phone应用时。
还必须添加它以被忽略,否则VS会报错:
mc:Ignorable="d win wp"
mc:Ignorable属性确保新的xmlns前缀被设计器和编译器忽略。
有了条件编译命名空间,现在可以输入以下XAML。现在只需要为控件添加前缀“win”或“wp”。在这里的例子中,希望TopAppBar只在它是Windows商店应用时显示,所以将“win”添加到“Page.TopAppBar”。
还添加了“wp”到“Page.BottomAppBar”。现在它只会编译到Windows Phone应用。
如果运行Windows应用,它将只显示顶部应用栏。如果运行Windows Phone应用,它将只显示命令栏。
当将自定义前缀应用于XML元素时,IntelliSense不起作用。但是,可以通过添加mc:ProcessContent属性来启用IntelliSense支持:
mc:ProcessContent="win:* wp:*"
mc:ProcessContent属性启用了条件区域内的IntelliSense。
不要使用#else if、#elif或#elsif,它们不起作用。可以使用#elif。
XCC处于测试阶段,所以请谨慎使用。
如果对特定控件使用XCC,将无法在设计时看到它。技巧是先设计它,当对它满意时,再应用条件编译。