簡體   English   中英

在一個庫/NuGet 包中支持多個版本的 NuGet 包

[英]Supporting multiple versions of NuGet package in one library / NuGet package

我想要的是

我希望我的庫能夠使用一系列版本的 NuGet 包,並在這些更改之間對 API 進行重大更改。 我沒有進一步調查,但這條路看起來很有希望:

  • 通過指定extern namespace aliases來引用具有不同 API 的庫的所有版本。
  • 為所需的類創建代理,使用標志/異常/任何東西來說明實際支持的內容。
  • 根據實際加載到應用程序中的版本,在運行時選擇正確的代理。
  • 依賴於不存在的 API 的代碼將不會被調用,所以一切都應該可以正常工作。

雖然這看起來很復雜,但與在單獨的程序集中支持每個版本的更直接的方法相比,它有很多好處:

  • 我的庫版本不會像 1.2.3-for-2.3.4-to-2.6.8 那樣亂七八糟。 我什至不知道在這種情況下版本控制應該如何工作。
  • NuGet 用戶不必在多個包之間進行選擇,一個包適合所有人。
  • 升級版本很簡單,不需要刪除和添加我的包。

問題

但是,目前尚不清楚這是否可能。 甚至在使用代理和檢測當前版本之前,我都堅持使用基礎知識。

我什至無法將多個PackageReference節點添加到 my.csproj,實際上只有一個引用有效。 有一種解決方法可以添加 NuGet 不直接支持的外部別名,但我無法做到這一點,因為我無法獲得兩個引用。 如果我以某種方式得到兩個,我將無法區分它們。

問題

  1. 是否可以使用 extern 命名空間別名和代理以這種方式實現對多個版本的支持?
  2. 如果是,如何添加對 NuGet 包的多個版本的引用並在代碼中使用它們?
  3. 如果不是,那么正確的方法是什么?

背景

我正在使用 CsConsoleFormat 庫來格式化控制台輸出。 我想直接支持流行的命令行包的所有相關版本,這樣漂亮的命令行幫助和類似的東西幾乎不需要編碼就可以添加,不管使用什么命令行解析庫。

我想聲明“我只支持最新版本”在我的情況下是可以接受的,但我寧願得到更廣泛的支持,即使它更復雜。 理想情況下,我想要一個 NuGet 包,它聲明對最低支持版本的依賴,但支持最新版本的所有內容

到目前為止的進展

我有點讓它工作,但有很多問題。 有關詳細信息,請參閱GitHub NuGet 主頁上的問題

如果您堅持使用外部別名 - 您可以直接添加多個版本引用,作為 dll 文件,而不是作為 nuget 包。

假設我想依賴 Newtonsoft.Json 包版本 10.0.3+。 但是,如果用戶安裝了版本 11 - 我想使用僅在此版本 (11) 中可用的通用JsonConverter<T>類。 然后我的 csproj 可能看起來像這樣:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <Version>1.0.4</Version>
  </PropertyGroup>
  <ItemGroup>
    <!-- Nuget reference -->
    <!-- Only this one will be included as dependency to the packed nuget -->
    <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
  </ItemGroup>
  <ItemGroup>
    <!-- Direct reference to the specific version -->
    <Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
      <!-- Path to v11 dll -->
      <HintPath>Newtonsoft.Json.v11.dll</HintPath>
      <Aliases>js11</Aliases>
      <SpecificVersion>true</SpecificVersion>
    </Reference>    
  </ItemGroup>
</Project>

然后我有代理接口:

public interface ISerializer {
    string Serialize<T>(T obj);
}

還有兩個實現,v10(使用全局的、非別名的命名空間):

using System;
using global::Newtonsoft.Json;

namespace NugetRefMain {
    internal class Js10Serializer : ISerializer
    {
        public string Serialize<T>(T obj)
        {
            Console.WriteLine(typeof(JsonConvert));
            return JsonConvert.SerializeObject(obj);
        }
    }
}

和 v11

extern alias js11;
using System;
using js11::Newtonsoft.Json;

namespace NugetRefMain {
    internal class Js11Serializer : ISerializer {
        public string Serialize<T>(T obj) {
            // using JsonConverter<T>, only available in v11
            Console.WriteLine(typeof(JsonConverter<T>));
            return JsonConvert.SerializeObject(obj);
        }
    }
}

最后是根據當前可用的 json.net 版本創建序列化程序的工廠:

public static class Serializers {
    public static ISerializer Create() {
        var version = typeof(JsonConvert).Assembly.GetName().Version;
        if (version.Major == 10)
            return new Js10Serializer();
        return new Js11Serializer();
    }
}

現在,如果我將其打包為 nuget - 它將對Newtonsoft.Json版本10.0.3具有單一依賴性,僅此而已。 但是,如果用戶安裝版本 11 的Newtonsoft.Json - 它將使用此版本中可用的功能。

缺點:

  • Visual Studio \ Resharper intellisense 有時不喜歡這種方法,並且在實際上一切都編譯得很好時顯示 intellisense 錯誤。

  • 您可能會在編譯時收到“版本沖突”警告。

NuGet 僅解析單個包版本。

如果你聲明對最低支持版本的依賴,任何引用項目都可以將依賴升級到更新的版本。

只要依賴包的作者不引入重大更改,它就應該可以找到。

即使您使用反射查看實際使用的程序集版本,您也會發現許多包作者不會在發布之間更改程序集版本。 這是為了避免在經典 .NET Framework 項目中綁定重定向的需要,因為所有版本都相同,並且 NuGet 將根據使用項目的已解析包版本選擇正確的 DLL。 同樣,只要沒有重大變化,這就很好。

您可以用來支持不同包的模式是提供許多消費者可以從中選擇的“平台”包。 然后,特定於平台的包將引用具有可共享邏輯的通用包。

“平台”將是例如“MyLogic.XUnit”或“MyLogic.NUnit”(假設以測試助手為例)引用“MyLogic.Common”

這不是一個完整的答案,但我在您的GitHub 問題頁面上注意到您在項目中引用了 .NET Standard 和 .NET Framework 庫。 已知這無法正常工作。

引用 .NET Standard 團隊的公告

.. 另一個症狀是在構建時關於程序集版本的警告..

這可能是你遇到的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM