首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 深度入門(五):類別庫開發、NuGet 封裝與跨專案復用實戰

     編輯:關於C語言

前言:程式碼復用的進化——從複製貼上到套件管理

隨著專案增長,將共用邏輯抽離為類別庫是架構演進的必經之路。.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>

二、設計公開 API:MathLib 核心實作

命名空間規劃

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;
        }
    }
}

API 設計原則

  • 介面導向:公開介面 + 內部實作,便於測試替換與解耦
  • 最小公開面:`internal` 預設,僅必要類別/成員標記 `public`
  • 不可變性:傾向傳回新物件而非修改現有物件
  • 非同步優先:I/O 操作提供 `Task` 版本
  • 文件註解:所有公開成員必須有 `///` XML 註解

三、建置、測試與封裝

建置驗證

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  # 套件參考 (模擬生產)

四、NuGet 套件發佈策略

1. 官方 nuget.org (公共開源)

# 取得 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

2. 私有伺服器 (企業內部)

  • Azure Artifacts:Azure DevOps 整合,支援 Pipeline 發佈
  • GitHub Packages:GitHub 原生,權限綁定 Repo/Org
  • MyGet / ProGet / Nexus / Artifactory:獨立套件伺服器
  • 本地資料夾/網路共享:簡單、無認證、適合小團隊

3. CI/CD 自動化發佈

# 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 測試。

Central Package Management (CPM)

<!-- 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>

偵錯套件程式碼

  • 套件含 `true` + Source Link → VS 自動下載原始碼、逐步進入
  • 本地開發:專案參考 (`ProjectReference`) 即時反映變更,無需重新封裝

六、進階主題

多目標框架

<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>

<!-- 條件編譯 -->
#if NET8_0
// 使用 Span, IAsyncEnumerable 等新 API
#else
// 相容實作
#endif

原始碼套件 (Source-only Package)

  • 僅包含 `.cs` 檔案,消費端編譯時併入專案
  • 適用於:Analyzer、Source Generator、極輕量工具
  • `false` + ``

Native AOT 相容性

  • 避免 `reflection`、`dynamic`、`Assembly.Load`、非 Blittable 型別 P/Invoke
  • 標記 `[RequiresUnreferencedCode]`、`[RequiresDynamicCode]` 屬性
  • 測試:`dotnet publish -c Release -r win-x64 -p:PublishAot=true`

七、常見問題排查

  1. 版本衝突:菱形相依 → 統一版本、Binding Redirect (Framework)、`PackageReference` 自動解析
  2. 找不到組件:`CopyLocalLockFileAssemblies=true` 確保輸出目錄含所有相依
  3. 循環相依:抽離共用介面至獨立套件
  4. 私有資源存取:`Assembly.GetManifestResourceStream` 讀取嵌入資源
  5. 套件降級警告:`NU1605` → 升級相依套件或容忍 (`NoWarn=NU1605`)

總結

類別庫 + NuGet 是 .NET 生態系統程式碼復用的基石。從「專案參考」開始開發,到「套件參考」釋出生產,再到「中央套件管理」統一版本,「私有源」隔離內部資產,「CI/CD」自動化發佈,形成完整的元件治理流程。掌握 API 設計原則、多目標框架、Source Link 偵錯、版本策略,能讓團隊高效建構、分享、演進共用元件,避免重複造輪子,專注核心業務創新。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved