繁体   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