本文將介紹如何使用 .NET CLI 撰寫 .NET 函式庫。 CLI 提供可在所有支援的作業系統上運作的有效率且低階體驗。 你仍然可以用 Visual Studio 來建立函式庫,如果你偏好那樣的體驗請參考 Visual Studio 指南。
必要條件
你需要在你的電腦上安裝 .NET SDK。
關於本文件中涉及 .NET Framework 版本的部分,你需要在 Windows 機器上安裝 .NET Framework。
此外,如果你想支援較舊的 .NET Framework 目標,你需要從 .NET Framework 下載頁面安裝目標包或開發者包。 請參閱這張表格︰
| .NET 框架版本 | 要下載的項目 |
|---|---|
| 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 軟體開發工具包 |
| 4.0 | Windows 7 與 .NET Framework 4 的 Windows SDK |
| 2.0、3.0 和 3.5 | .NET Framework 3.5 SP1 執行時(或 Windows 8+ 版本) |
如何針對 .NET 5+ 或 .NET 標準
若想控制專案的目標 Framework,可將其新增至專案檔 (.csproj 或 .fsproj)。 關於如何選擇目標.NET 5+或.NET標準,請參閱.NET 5+及.NET標準。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>
如果你想針對 .NET Framework 4.0 或更低版本,或想使用 .NET Framework 中有但 .NET Standard 沒有的 API(例如 System.Drawing),請閱讀以下章節並學習如何多目標。
如何針對 .NET 框架
備註
這些說明假設你的電腦上已經安裝了 .NET Framework。 請參閱安裝相依性的必要條件。
請注意,這裡使用的部分 .NET Framework 版本已不再支援。 請參閱 .NET框架支援生命週期政策常見問題關於未受支援版本的說明。
如果你想達到最多開發者和專案,就以 .NET Framework 4.0 作為基準目標。 要針對 .NET 框架,請先使用對應您希望支援的 .NET 框架版本的正確目標框架名稱(TFM)。
| .NET 框架版本 | TFM |
|---|---|
| .NET 框架 2.0 | net20 |
| .NET 框架 3.0 | net30 |
| .NET 框架 3.5 | net35 |
| .NET 框架 4.0 | net40 |
| .NET 框架 4.5 | net45 |
| .NET 框架 4.5.1 | net451 |
| .NET 框架 4.5.2 | net452 |
| .NET 框架 4.6 | net46 |
| .NET 框架 4.6.1 | net461 |
| .NET 框架 4.6.2 | net462 |
| .NET 框架 4.7 | net47 |
| .NET 框架 4.8 | net48 |
您接著將這個 TFM 插入專案檔的 區段。 舉例來說,以下是你如何撰寫針對 .NET Framework 4.0 的函式庫:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net40</TargetFramework>
</PropertyGroup>
</Project>
就這麼簡單! 雖然此函式庫僅編譯為 .NET Framework 4,但你可以在較新版本的 .NET Framework 中使用該函式庫。
如何同時瞄準多個目標
備註
以下說明假設你已經在機器上安裝了 .NET 框架。 請參閱必要條件小節,了解您需要安裝的相依性以及其下載位置。
當你的專案同時支援 .NET Framework 和 .NET 時,你可能需要針對較舊版本的 .NET 框架。 在這個案例中,如果您想要為較新的目標使用較新的 API 和語言建構,請在程式碼中使用 指示詞。 您也可能需要針對設為目標的每個平台新增不同的套件和相依性,以包含每個案例所需的不同 API。
例如,假設您的程式庫透過 HTTP 執行網路作業。 對於 .NET Standard 和 .NET Framework 4.5 或更高版本,你可以使用 HttpClient 命名空間中的 System.Net.Http 類別。 不過,早期版本的 .NET Framework 沒有 HttpClient 類別,因此你可以使用 WebClient 命名空間中的 System.Net 類別來替代這些類別。
專案檔如下所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;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>
您可在這裡發現三個主要變更︰
- 節點已取代為 ,而且其內表示三個 TFM。
- 有一個
<ItemGroup>節點用於拉取一個 .NET Framework 參考中的net40目標。 - 有一個
<ItemGroup>節點用於net45目標,引入兩個 .NET Framework 參考。
前置處理器符號
建置系統會得知 指示詞中所使用的下列前置處理器符號︰
| 目標框架 | 符號 | 其他符號 (以 .NET 5+ SDK 提供) |
平台符號(僅限於某些平台) 當您指定 OS 特定的 TFM 時 |
|---|---|---|---|
| .NET 框架 | 、、、、、、、、、、、、、、 | 、、、、、、、、、、、、 | |
| .NET 標準 | 、、、、、、、、、 | 、、、、、、、、 | |
| .NET 5+(以及 .NET 核心) | 、、、、、、、、、、、、、、 | 、、、、、、、、、、、、 | 、、、、、、、、 (例如 )、 (例如 ) |
備註
- 無論您的目標版本為何,系統都會定義無版本符號。
- 系統只會針對您設定為目標的版本定義版本特定符號。
- 系統會針對您的目標版本和所有更早版本定義 符號。 例如,如果你針對 .NET Framework 2.0,定義的符號包括
NET20、NET20_OR_GREATER、NET11_OR_GREATER和NET10_OR_GREATER。 -
NETSTANDARD<x>_<y>_OR_GREATER符號僅針對 .NET Standard 目標定義,不包括實作 .NET Standard(如 .NET Core 和 .NET Framework)的目標。 - 這些與 MSBuild 屬性和 NuGet 所使用的目標 Framework Moniker (TFM) 不同。
以下是利用個別目標之條件式編譯的範例︰
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 = "https://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 Framework 4.5+ can use async/await!
public async Task<string> GetDotNetCountAsync()
{
string url = "https://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
}
}
如果您使用 建置此專案,則會在 資料夾下方發現三個目錄:
net40/
net45/
netstandard2.0/
每個資料夾都包含各個目標的 檔案。
如何在 .NET 上測試函式庫
重要的是一定要可以跨平台進行測試。 您可以使用現成的 xUnit 或 MSTest。 這兩種都非常適合用來測試你的 .NET 函式庫。 如何設定具有測試專案的方案,將取決於方案結構。 下列範例假設測試及來源目錄位於相同的最上層目錄中。
備註
這會使用一些 .NET CLI 指令。 如需詳細資訊,請參閱 dotnet new 及 dotnet sln。
設定您的方案。 您可以使用下列命令:
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.sln |__MyProject/ |__MyProject.Test/巡覽至測試專案的目錄,並將參考從 新增至 。
cd MyProject.Test dotnet reference add ../MyProject/MyProject.csproj還原套件並編譯專案︰
dotnet restore dotnet build執行 命令,確認已執行 xUnit。 如果您選擇使用 MSTest,則 MSTest 控制台執行器會執行。
就這麼簡單! 您現在可以使用命令列工具在所有平台上測試程式庫。 若要在設定好所有項目之後繼續進行測試,測試您的函式庫將非常簡單︰
- 對程式庫進行變更。
- 在測試目錄中,從命令列中使用 命令來執行測試。
當您叫用 命令時,將會自動重建程式碼。
如何使用多個專案
較大程式庫的常見需求是將功能放在不同的專案中。
假設您想要建置可在慣用 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 - 專案,具有公用 API 可供在 C# 中使用
- AwesomeLibrary.FSharp - 專案,具有公用 API 可供在 F# 中使用
您可以在終端機中執行下列命令,以產生與本指南相同的結構︰
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 CLI 來新增專案參考。 從 AwesomeLibrary.CSharp 及 AwesomeLibrary.FSharp 專案目錄中,您可以執行下列命令︰
dotnet reference add ../AwesomeLibrary.Core/AwesomeLibrary.Core.csproj
AwesomeLibrary.CSharp 及 AwesomeLibrary.FSharp 的專案檔現在參考 AwesomeLibrary.Core 作為 目標。 檢查專案檔並查看其中的下列內容,即可確認這項作業︰
<ItemGroup>
<ProjectReference Include="..\AwesomeLibrary.Core\AwesomeLibrary.Core.csproj" />
</ItemGroup>
如果你不想使用 .NET CLI,可以手動將這個區段加入每個專案檔案。
架構化方案
多專案方案的另一個重要部分是建立不錯的整體專案結構。 不過,您可以視需要組織程式碼,而且只要您使用 將每個專案連結至方案檔,就可以在方案層級執行 及 。