隨著專案增長,將共用邏輯抽離為類別庫是架構演進的必經之路。.NET 採用「組件」作為部署單位,配合 NuGet 套件管理器,實現跨專案、跨團隊、跨組織的程式碼分享與版本控制。本章完整演示:建立類別庫專案、設計公開 API、產生 NuGet 套件、本地/私有/公共源發佈、消費端引用與版本管理策略。
| 範本 | 目標框架 | 適用場景 |
|---|---|---|
| 類別庫 | .NET Standard 2.0 / .NET 8.0 | 跨平台共用邏輯(推薦 .NET Standard 2.0 最大相容性) |
| WPF 類別庫 | .NET 8.0-windows | 包含 WPF 控制項/視窗的 UI 元件庫 |
| Windows Forms 類別庫 | .NET 8.0-windows | 包含 WinForms 控制項的 UI 元件庫 |
dotnet new classlib -n MyMathLib -f netstandard2.0
# 或
dotnet new classlib -n MyMathLib -f net8.0
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- 建置時自動產生 .nupkg -->
<PackageId>MyCompany.MathLib</PackageId>
<Version>1.0.0</Version>
<Authors>Your Name</Authors>
<Company>MyCompany</Company>
<Description>核心數學運算共用元件</Description>
<PackageTags>math;utility;core</PackageTags>
<RepositoryUrl>https://github.com/your/repo</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<IncludeSymbols>true</IncludeSymbols> <!-- 包含 .pdb 供偵錯 -->
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<!-- 專案參考來源連結 (Source Link) -->
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>
</Project>
namespace MyCompany.MathLib
{
// 公開介面
public interface ICalculator
{
long Add(long a, long b);
long Subtract(long a, long b);
long Multiply(long a, long b);
double Divide(double a, double b);
}
// 預設實作
public class Calculator : ICalculator
{
public long Add(long a, long b) => a + b;
public long Subtract(long a, long b) => a - b;
public long Multiply(long a, long b) => a * b;
public double Divide(double a, double b) => b != 0 ? a / b : throw new DivideByZeroException();
}
// 擴充方法 (獨立靜態類別)
public static class MathExtensions
{
public static bool IsEven(this int value) => value % 2 == 0;
public static bool IsPrime(this int value)
{
if (value < 2) return false;
for (int i = 2; i * i <= value; i++)
if (value % i == 0) return false;
return true;
}
}
}
dotnet build -c Release
# 輸出:bin/Release/netstandard2.0/MyMathLib.dll
# 同步產生:bin/Release/MyCompany.MathLib.1.0.0.nupkg
dotnet new xunit -n MyMathLib.Tests
dotnet add MyMathLib.Tests reference MyMathLib/MyMathLib.csproj
public class CalculatorTests
{
private readonly ICalculator _calc = new Calculator();
[Fact] public void Add_TwoPositives_ReturnsSum() => Assert.Equal(5, _calc.Add(2, 3));
[Fact] public void Divide_ByZero_Throws() => Assert.Throws(() => _calc.Divide(1, 0));
[Theory] [InlineData(2, true)] [InlineData(3, false)] public void IsEven_Works(int n, bool expected) => Assert.Equal(expected, n.IsEven());
}
dotnet test -c Release
# 建立本地套件源
dotnet nuget add source ./nupkgs -n LocalPackages
# 消費端引用
dotnet add MyApp reference MyMathLib/MyMathLib.csproj # 專案參考 (開發時)
dotnet add MyApp package MyCompany.MathLib --source LocalPackages # 套件參考 (模擬生產)
# 取得 API Key (nuget.org 帳號 → API Keys)
dotnet nuget push bin/Release/MyCompany.MathLib.1.0.0.nupkg -k YOUR_API_KEY -s https://api.nuget.org/v3/index.json
# GitHub Actions 範例
- name: Pack & Push
run: |
dotnet pack -c Release -o ./artifacts
dotnet nuget push ./artifacts/*.nupkg -k ${{ secrets.NUGET_KEY }} -s https://api.nuget.org/v3/index.json
env:
NUGET_KEY: ${{ secrets.NUGET_KEY }}
| 策略 | 版本格式 | 更新行為 | 風險 |
|---|---|---|---|
| 精確版本 | 1.2.3 | 鎖定版本,手動升級 | 低,但需手動維護 |
| 次要版本浮動 | 1.2.* | 自動取得最新 Patch | 中,可能引入 Bug |
| 主要版本浮動 | 1.* | 自動取得最新 Minor/Patch | 高,破壞性變更風險 |
建議:專案鎖定精確版本,依賴更新透過 Dependabot/Renovate Bot 自動發 PR 測試。
<!-- Directory.Packages.props (方案根目錄) -->
<Project>
<ItemGroup>
<PackageVersion Include="MyCompany.MathLib" Version="1.0.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>
<!-- 專案檔 -->
<Project>
<ItemGroup>
<PackageReference Include="MyCompany.MathLib" /> <!-- 版本由中央管理 -->
</ItemGroup>
</Project>
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
<!-- 條件編譯 -->
#if NET8_0
// 使用 Span, IAsyncEnumerable 等新 API
#else
// 相容實作
#endif
類別庫 + NuGet 是 .NET 生態系統程式碼復用的基石。從「專案參考」開始開發,到「套件參考」釋出生產,再到「中央套件管理」統一版本,「私有源」隔離內部資產,「CI/CD」自動化發佈,形成完整的元件治理流程。掌握 API 設計原則、多目標框架、Source Link 偵錯、版本策略,能讓團隊高效建構、分享、演進共用元件,避免重複造輪子,專注核心業務創新。