.NET探索平臺條件編譯
阿新 • • 發佈:2021-01-18
## 前言
今天偶然機會,翻了一下大學期間的書籍《C程式設計》,好吧,當我翻著翻著,翻到了符號常量(`#define`指令)中,是啊,這是一個前處理器指令,記得在[Magicodes.IE](https://github.com/dotnetcore/Magicodes.IE/blob/master/src/Magicodes.ExporterAndImporter.Pdf/PdfExporter.cs#L51)中針對平臺選擇不同的庫,哈哈,這是一個典型的根據平臺進行條件處理,好吧,根據這些內容,讓我感覺在今天,我需要對`#define`指令以及在.NET中的平臺條件處理,以及平臺的條件編譯進行記錄一下。
## define
我們可通過`define`來定義符號,然後將符號用在`#if`指令表示式中,如下所示:
```csharp
#define PI
```
通過上面這些內容可能很難去了解這該如何使用,其實`#define`在我們的編碼過程中也是很少去使用的,我們繼續往下看。
其實對於前處理器,在我們除錯以及執行時的作用是比較大的,比如說對某些程式碼限制編譯,另一方變其實還可以對程式碼進行環境或者版本的控制,這些都是Ok的,最後我們結合著控制語句`#if`來看一下:
```csharp
#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`屬性進行操作。
![file](https://blog.stackable.cn/uploads/img-daae016b-d67a-4975-9ace-aeffc150928e.png)
我們可以開啟專案檔案進行檢視,屬性如下所示:
```
Exe
net5
TRACE;PI
```
當然了,我們一方面是可通過VS對專案的屬性進行編輯,而另一方面,我們是可通過直接對專案檔案進行修改編輯操作.這樣其實達到了一個可控制性.
## RuntimeInformation
對於程式碼中也是可以進行平臺的邏輯判斷的,在`.NET Core 1.0`的時候其實已經添加了`System.Runtime.InteropServices.RuntimeInformation`對於這個類的新增,使我們可以動態的去判斷當前的作業系統(OS),以及我們可通過這些動態判斷為我們的業務邏輯進行不同的處理行為。
判斷當前作業系統如下所示:
```csharp
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`如下所示:
```
Exe
net5
true
true
true
```
我們是可以通過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,說明我們的操作生效了,那麼我們繼續修改我們的程式,看看如何使用條件編譯,去控制我們的程式碼,我們在專案檔案中新增如下片段:
```
Windows
OSX
Linux
```
通過如上語句,我們可以對`DefineConstants`屬性進行條件判斷,條件性處理,同樣我們在程式碼中也是通過該值進行判斷,如下所示:
```csharp
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://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-define?WT.mc_id=DT-MVP-5003855)
https://blog.walterlv.com/post/how-to-define-preprocessor-symbols.html