前言
今天偶然機會,翻了一下大學期間的書籍《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://blog.walterlv.com/post/how-to-define-preprocessor-symbols.html