前言
今天偶然机会,翻了一下大学期间的书籍《C程序设计》,好吧,当我翻着翻着,翻到了符号常量(#define
指令)中,是啊,这是一个预处理器指令,记得在Magicodes.IE中针对平台选择不同的库,哈哈,这是一个典型的根据平台进行条件处理,好吧,根据这些内容,让我感觉在今天,我需要对#define
指令以及在.NET中的平台条件处理,以及平台的条件编译进行记录一下。
define
我们可通过define
来定义符号,然后将符号用在#if
指令表达式中,如下所示:
#define PI
通过上面这些内容可能很难去了解这该如何使用,其实#define
在我们的编码过程中也是很少去使用的,我们继续往下看。
其实对于预处理器,在我们调试以及运行时的作用是比较大的,比如说对某些代码限制编译,另一方变其实还可以对代码进行环境或者版本的控制,这些都是Ok的,最后我们结合着控制语句#if
来看一下:
#define PI
using System;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
#if (PI)
Console.WriteLine("PI is defined");
#else
Console.WriteLine("PI is not defined");
#endif
Console.ReadKey();
}
}
}
当我们的头部声明#define PI
时,我们也可以看到编译的感知功能可以为我们将控制语句进行切换,是啊,我们可以在头部进行声明。
条件编译符号
对于上面我们可以直接通过#define
去进行条件编译,而对于在.cs
文件中我们去定义它达到的只是局部的使用,我们如果说想全局的控制,全局的应用该如何操作?其实我们是可以通过DefineConstants
属性进行操作。
我们可以打开项目文件进行查看,属性如下所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;PI</DefineConstants>
</PropertyGroup>
</Project>
当然了,我们一方面是可通过VS对项目的属性进行编辑,而另一方面,我们是可通过直接对项目文件进行修改编辑操作.这样其实达到了一个可控制性.
RuntimeInformation
对于代码中也是可以进行平台的逻辑判断的,在.NET Core 1.0
的时候其实已经添加了System.Runtime.InteropServices.RuntimeInformation
对于这个类的添加,使我们可以动态的去判断当前的操作系统(OS),以及我们可通过这些动态判断为我们的业务逻辑进行不同的处理行为。
判断当前操作系统如下所示:
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
Console.WriteLine("Running on Linux!");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
Console.WriteLine("Running on macOS!");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Console.WriteLine("Running on Windows!");
MSBuild & RuntimeInformation
对于条件编译,之前我们已经手动的操作过一次了,是我们可以根据不同的环境值进行对代码编译内容的控制,如果说我想根据当前的操作系统(OS)动态的进行条件编译,该如何进行操作。
其实我们在项目文件中进行调用System.Runtime.InteropServices.RuntimeInformation
进行我们的条件处理。下面我们看一下在MSBuild中如何调用System.Runtime.InteropServices.RuntimeInformation
如下所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5</TargetFramework>
<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">true</IsWindows>
<IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</IsOSX>
<IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">true</IsLinux>
</PropertyGroup>
<Target Name="PrintRID" BeforeTargets="Build">
<Message Text="IsWindows $(IsWindows)" Importance="high" />
<Message Text="IsOSX $(IsOSX)" Importance="high" />
<Message Text="IsLinux $(IsLinux)" Importance="high" />
</Target>
</Project>
我们是可以通过visual studio或者说通过CLI直接运行构建命令dotnet build
,我们在Windows操作系统中测试一下,输出结果如下所示:
C:\Users\hueif\source\repos\ConsoleApp2\ConsoleApp2>dotnet build
用于 .NET 的 Microsoft (R) 生成引擎版本 16.8.0+126527ff1
版权所有(C) Microsoft Corporation。保留所有权利。
正在确定要还原的项目…
所有项目均是最新的,无法还原。
你正在使用 .NET 的预览版。请查看 https://aka.ms/dotnet-core-preview
ConsoleApp2 -> C:\Users\hueif\source\repos\ConsoleApp2\ConsoleApp2\bin\Debug\net5\ConsoleApp2.dll
IsWindows true
IsOSX
IsLinux
可以看出,在IsWindows
中对应着true,说明我们的操作生效了,那么我们继续修改我们的程序,看看如何使用条件编译,去控制我们的代码,我们在项目文件中添加如下片段:
<PropertyGroup Condition="'$(IsWindows)'=='true'">
<DefineConstants>Windows</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(IsOSX)'=='true'">
<DefineConstants>OSX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(IsLinux)'=='true'">
<DefineConstants>Linux</DefineConstants>
</PropertyGroup>
通过如上语句,我们可以对DefineConstants
属性进行条件判断,条件性处理,同样我们在代码中也是通过该值进行判断,如下所示:
static void Main(string[] args)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
Console.WriteLine("Running on Linux!");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
Console.WriteLine("Running on macOS!");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Console.WriteLine("Running on Windows!");
#if Linux
Console.WriteLine("Build on Linux!");
#elif OSX
Console.WriteLine("Build on macOS!");
#elif Windows
Console.WriteLine("Build in Windows!");
#endif
Console.ReadKey();
}
下面我们来验证一下结果,是否跟我们想象中的一样
Running on Windows!
Build in Windows!
结果没问题,已达到预期的效果。
References
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-define
https://blog.walterlv.com/post/how-to-define-preprocessor-symbols.html