使用跨平臺工具開發庫 本文介紹如何使用跨平臺 CLI 工具編寫 .NET 的庫。 CLI 提供可跨任何支持的 OS 工作的高效低級別體驗。 仍可使用 Visual Studio 生成庫,如果你首選這種體驗,請 "參閱 Visual Studio 指南" 。 先決條件 需要在電腦上安裝 ".NET ...
使用跨平臺工具開發庫
本文介紹如何使用跨平臺 CLI 工具編寫 .NET 的庫。 CLI 提供可跨任何支持的 OS 工作的高效低級別體驗。 仍可使用 Visual Studio 生成庫,如果你首選這種體驗,請參閱 Visual Studio 指南。
先決條件
需要在電腦上安裝 .NET Core SDK 和 CLI 。
對於本文檔中處理 .NET Framework 版本的部分,需要在 Windows 電腦上安裝 .NET Framework。
此外,如果想要支持較舊的 .NET Framework 目標,需要從 .NET 目標平臺頁面安裝用於較舊 Framework 版本的目標包/開發人員工具包。 請參閱此表:
.NET Framework 版本 | 下載內容 |
---|---|
4.6.1 | .NET Framework 4.6.1 目標包 |
4.6 | .NET Framework 4.6 目標包 |
4.5.2 | .NET Framework 4.5.2 開發人員工具包 |
4.5.1 | .NET Framework 4.5.1 開發人員工具包 |
4.5 | 適用於 Windows 8 的 Windows 軟體開發工具包 |
4.0 | Windows SDK for Windows 7 和 .NET Framework 4 |
2.0、3.0 和 3.5 | .NET Framework 3.5 SP1 運行時(或 Windows 8+ 版本) |
如何以 .NET Standard 為目標
如果對 .NET Standard 不是很熟悉,請參閱 瞭解詳細信息。
在該文中,提供有一個將 .NET Standard 版本映射到各種實現的表格:
[!INCLUDE net-standard-table]
以下是此表格對於創建庫的意義:
選擇 .NET Standard 版本時,需要在能夠訪問最新 API 與能夠定位更多 .NET 實現代碼和 .NET Standard 版本之間進行權衡。 通過選擇 netstandardX.X
版本(其中 X.X
是版本號)並將其添加到項目文件(.csproj
或 .fsproj
),控制可面向的平臺和版本範圍。
面向 .NET Standard 時,有三種主要選項,具體取決於你的需求。
可使用 .NET Standard 的預設版本,該版本由
netstandard1.4
模板提供,可提供對 .NET Standard 上大多數 API 的訪問許可權,同時仍與 UWP、.NET Framework 4.6.1 和即將推出的 .NET Standard 2.0 相容。<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard1.4</TargetFramework> </PropertyGroup> </Project>
可通過修改項目文件
TargetFramework
節點中的值來使用更低或更高版本的 .NET Standard。.NET Standard 版本可後向相容。 這意味著
netstandard1.0
庫可在netstandard1.1
平臺以及更高版本上運行。 但是,不可向前相容,即版本較低的 .NET Standard 平臺無法引用版本較高的平臺。 這意味著netstandard1.0
庫不能引用面向netstandard1.1
或更高版本的庫。 選擇適合所需、恰當混合有 API 和平臺支持的 Standard 版本。 目前,我們建議netstandard1.4
。如果希望面向 .NET Framework 版本 4.0 或更低版本,或者要使用 .NET Framework 中提供但 .NET Standard 中不提供的 API(例如
System.Drawing
),請閱讀以下部分,瞭解如何設定多目標。
如何以 .NET Framework 為目標
[!NOTE]
這些說明假定電腦上安裝有 .NET Framework。 請參閱先決條件 獲取安裝的依賴項。
請記住,此處使用的某些 .NET Framework 版本不再受支持。 有關不受支持的版本信息,請參閱 .NET Framework 支持生命周期策略常見問題。
如果要達到最大數量的開發人員和項目,可將 .NET Framework 4.0 用作基線目標。 若要以 .NET Framework 為目標,首先需要使用與要支持的 .NET Framework 版本相對應的正確目標框架名字對象 (TFM)。
.NET Framework 2.0 --> net20
.NET Framework 3.0 --> net30
.NET Framework 3.5 --> net35
.NET Framework 4.0 --> net40
.NET Framework 4.5 --> net45
.NET Framework 4.5.1 --> net451
.NET Framework 4.5.2 --> net452
.NET Framework 4.6 --> net46
.NET Framework 4.6.1 --> net461
.NET Framework 4.6.2 --> net462
.NET Framework 4.7 --> net47
然後將此 TFM 插入項目文件的 TargetFramework
部分。 例如,以下是如何編寫面向 .NET Framework 4.0 的庫:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net40</TargetFramework>
</PropertyGroup>
</Project>
就是這麼簡單! 雖然此庫僅針對 .NET Framework 4 編譯,但可在較新版本的 .NET Framework 上使用此庫。
如何設定多目標
[!NOTE]
以下說明假定電腦上安裝有 .NET Framework。 請參閱先決條件部分,瞭解需要安裝哪些依賴項以及在何處下載。
如果項目同時支持 .NET Framework 和 .NET Core,可能需要面向較舊版本的 .NET Framework。 在此方案中,如果要為較新目標使用較新的 API 和語言構造,請在代碼中使用 #if
指令。 可能還需要為要面向的每個平臺添加不同的包和依賴項,以包含每種情況所需的不同 API。
例如,假設有一個庫,它通過 HTTP 執行聯網操作。 對於 .NET Standard 和 .NET Framework 版本 4.5 或更高版本,可從 System.Net.Http
命名空間使用 HttpClient
類。 但是,.NET Framework 的早期版本沒有 HttpClient
類,因此可對早期版本使用 System.Net
命名空間中的 WebClient
類。
項目文件可能如下所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;net40;net45</TargetFrameworks>
</PropertyGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.0 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
<Reference Include="System.Net" />
</ItemGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.5 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.Net.Http" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
</Project>
在此處可看到三項主要更改:
TargetFramework
節點已替換為TargetFrameworks
,其中表示了三個 TFM。net40
目標有一個<ItemGroup>
節點,拉取一個 .NET Framework 引用。net45
目標中有一個<ItemGroup>
節點,拉取兩個 .NET Framework 引用。
生成系統可識別以下用在 #if
指令中的處理器符號:
[!INCLUDE Preprocessor symbols]
以下是使用每目標條件編譯的示例:
using System;
using System.Text.RegularExpressions;
#if NET40
// This only compiles for the .NET Framework 4 targets
using System.Net;
#else
// This compiles for all other targets
using System.Net.Http;
using System.Threading.Tasks;
#endif
namespace MultitargetLib
{
public class Library
{
#if NET40
private readonly WebClient _client = new WebClient();
private readonly object _locker = new object();
#else
private readonly HttpClient _client = new HttpClient();
#endif
#if NET40
// .NET Framework 4.0 does not have async/await
public string GetDotNetCount()
{
string url = "http://www.dotnetfoundation.org/";
var uri = new Uri(url);
string result = "";
// Lock here to provide thread-safety.
lock(_locker)
{
result = _client.DownloadString(uri);
}
int dotNetCount = Regex.Matches(result, ".NET").Count;
return $"Dotnet Foundation mentions .NET {dotNetCount} times!";
}
#else
// .NET 4.5+ can use async/await!
public async Task<string> GetDotNetCountAsync()
{
string url = "http://www.dotnetfoundation.org/";
// HttpClient is thread-safe, so no need to explicitly lock here
var result = await _client.GetStringAsync(url);
int dotNetCount = Regex.Matches(result, ".NET").Count;
return $"dotnetfoundation.org mentions .NET {dotNetCount} times in its HTML!";
}
#endif
}
}
如果使用 dotnet build
生成此項目,則在 bin/
文件夾下有三個目錄:
net40/
net45/
netstandard1.4/
其中每個目錄都包含每個目標的 .dll
文件。
如何在 .NET Core 上測試庫
能夠跨平臺進行測試至關重要。 可使用現成的 xUnit 或 MSTest。 它們都十分適合在 .NET Core 上對庫進行單元測試。 如何使用測試項目設置解決方案取決於解決方案的結構。 下麵的示例假設測試和源目錄位於同一頂級目錄下。
[!NOTE]
此示例將使用某些 .NET Core CLI 命令。 有關詳細信息,請參閱 dotnet new 和 dotnet sln。
- 設置解決方案。 可使用以下命令實現此目的:
bash mkdir SolutionWithSrcAndTest cd SolutionWithSrcAndTest dotnet new sln dotnet new classlib -o MyProject dotnet new xunit -o MyProject.Test dotnet sln add MyProject/MyProject.csproj dotnet sln add MyProject.Test/MyProject.Test.csproj
這將創建多個項目,並一個解決方案中將這些項目鏈接在一起。 SolutionWithSrcAndTest
的目錄應如下所示:
/SolutionWithSrcAndTest |__SolutionWithSrcAndTest.sln |__MyProject/ |__MyProject.Test/
- 導航到測試項目的目錄,然後添加對
MyProject
中的MyProject.Test
的引用。
bash cd MyProject.Test dotnet add reference ../MyProject/MyProject.csproj
- 還原包和生成項目:
bash dotnet restore dotnet build
- 執行
dotnet test
命令,驗證 xUnit 是否在運行。 如果選擇使用 MSTest,則應改為運行 MSTest 控制台運行程式。
就是這麼簡單! 現在可以使用命令行工具跨所有平臺測試庫。 若要繼續測試,現已設置好了所有內容,測試庫將非常簡單:
- 對庫進行更改。
- 使用
dotnet test
命令在測試目錄中從命令行運行測試。
調用 dotnet test
命令時,將自動重新生成代碼。
如何使用多個項目
對於較大的庫,通常需要將功能置於不同項目中。
假設要生成一個可以慣用的 C# 和 F# 使用的庫。 這意味著庫的使用者可通過對 C# 或 F# 來說很自然的方式來使用它們。 例如,在 C# 中,了能會這樣使用庫:
using AwesomeLibrary.CSharp;
public Task DoThings(Data data)
{
var convertResult = await AwesomeLibrary.ConvertAsync(data);
var result = AwesomeLibrary.Process(convertResult);
// do something with result
}
在 F# 中可能是這樣:
open AwesomeLibrary.FSharp
let doWork data = async {
let! result = AwesomeLibrary.AsyncConvert data // Uses an F# async function rather than C# async method
// do something with result
}
這樣的使用方案意味著被訪問的 API 必須具有用於 C# 和 F# 的不同結構。 通常的方法是將庫的所有邏輯因數轉化到核心項目中,C# 和 F# 項目定義調用到核心項目的 API 層。 該部分的其餘部分將使用以下名稱:
- AwesomeLibrary.Core - 核心項目,其中包含庫的所有邏輯
- AwesomeLibrary.CSharp - 具有打算在 C# 中使用的公共 API 的項目
- AwesomeLibrary.FSharp - 具有打算在 F# 中使用的公共 API 的項目
可在終端運行下列命令,生成與下列指南相同的結構:
mkdir AwesomeLibrary && cd AwesomeLibrary
dotnet new sln
mkdir AwesomeLibrary.Core && cd AwesomeLibrary.Core && dotnet new classlib
cd ..
mkdir AwesomeLibrary.CSharp && cd AwesomeLibrary.CSharp && dotnet new classlib
cd ..
mkdir AwesomeLibrary.FSharp && cd AwesomeLibrary.FSharp && dotnet new classlib -lang F#
cd ..
dotnet sln add AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
dotnet sln add AwesomeLibrary.CSharp/AwesomeLibrary.CSharp.csproj
dotnet sln add AwesomeLibrary.FSharp/AwesomeLibrary.FSharp.fsproj
這將添加上述三個項目和將它們鏈接在一起的解決方案文件。 創建解決方案文件並鏈接項目後,可從頂級還原和生成項目。
項目到項目的引用
引用項目的最佳方式是使用 .NET Core CLI 添加項目引用。 在 AwesomeLibrary.CSharp 和 AwesomeLibrary.FSharp 項目目錄中,可運行下列命令:
$ dotnet add reference ../AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
AwesomeLibrary.CSharp 和 AwesomeLibrary.FSharp 的項目文件現在需要將 AwesomeLibrary.Core 作為 ProjectReference
目標引用。 可通過檢查項目文件和查看其中的下列內容來進行驗證:
<ItemGroup>
<ProjectReference Include="..\AwesomeLibrary.Core\AwesomeLibrary.Core.csproj" />
</ItemGroup>
如果不想使用 .NET Core CLI,可手動將此部分添加到每個項目文件。
結構化解決方案
多項目解決方案的另一個重要方面是建立良好的整體項目結構。 可根據自己的喜好隨意組織代碼,只要使用 dotnet sln add
將每個項目鏈接到解決方案文件,就可在解決方案級別運行 dotnet restore
和 dotnet build
。