在一个库/ NuGet包中支持多个版本的NuGet包

Ath*_*ari 8 .net c# msbuild nuget

我想要的是

我希望我的库能够使用各种版本的NuGet包,并在更改之间对API进行重大更改.我没有进一步调查,但这条路看起来很有希望:

  • 通过指定extern命名空间别名来引用具有不同API的库的所有版本.
  • 为所需的类创建代理,使用flags/exceptions/what来告诉实际支持的内容.
  • 根据实际加载到应用程序中的版本,在运行时选择正确的代理.
  • 依赖于不存在的API的代码将不会被调用,因此一切都应该正常工作.

虽然这可能看起来很复杂,但它比在单独的程序集中支持每个版本的更直接的方法有许多好处:

  • 我的库的版本不会像1.2.3-for-2.3.4-to 2.6.8那样乱成一团.在这种情况下,我甚至不知道版本控制应该如何工作.
  • NuGet用户不必在几个包之间进行选择,一个包适合所有包.
  • 升级版本很简单,不需要删除和添加我的包.

问题

但是,目前还不清楚它是否可能.甚至在获得代理和检测当前版本之前,我就坚持了基础知识.

我甚PackageReference至无法向我的.csproj 添加多个节点,只有一个参考实际上有效.有一个解决方法来添加 NuGet不直接支持的外部别名,但我无法达到这一点,因为我无法获得两个引用.如果我以某种方式得到两个,我将无法区分它们.

问题

  1. 可以使用extern命名空间别名和代理以这种方式实现对多个版本的支持吗?
  2. 如果是,如何添加对NuGet包的多个版本的引用并在代码中使用它们?
  3. 如果没有,那么正确的方法是什么?

背景

我正在使用CsConsoleFormat库来格式化控制台输出.我希望直接支持流行的命令行软件包的所有相关版本,这样无论使用什么命令行解析库,都可以添加几乎没有编码的漂亮命令行帮助和类似的东西.

我想在我的案例中声称"我只支持最新版本"在某种程度上是可以接受的,但即使它更复杂,我也宁愿得到更广泛的支持.理想情况下,我想要一个NuGet包,它声明对最低支持版本的依赖,但支持最新版本的所有内容.

到目前为止进展

我有点工作,但有很多问题.有关详细信息,请参阅GitHub NuGet Home上的问题.

Evk*_*Evk 5

如果您坚持使用外部别名-您可以直接将多个版本引用添加为dll文件,而不是nuget包。

假设我想依赖于Newtonsoft.Json软件包10.0.3+版本。但是,如果用户安装了版本11-我想使用JsonConverter<T>仅在该版本(11)中可用的通用类。然后我的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>
Run Code Online (Sandbox Code Playgroud)

然后我有代理接口:

public interface ISerializer {
    string Serialize<T>(T obj);
}
Run Code Online (Sandbox Code Playgroud)

还有两个实现,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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是工厂,它根据当前可用的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我将其打包为nuget,它将对Newtonsoft.Json版本具有单一依赖性,仅此而已10.0.3。但是,如果用户安装Newtonsoft.Json版本11,它将使用该版本中可用的功能。

缺点:

  • Visual Studio \ Resharper intellisense有时不喜欢这种方法,并且在实际一切都可以编译的情况下显示intellisense错误。

  • 您可能在编译时有“版本冲突”警告。


Mar*_*ich 3

NuGet 仅解析单个包版本。

如果您声明对最低支持版本的依赖项,则任何引用项目都可以将该依赖项升级到较新的版本。

只要依赖包的作者不引入重大更改,find 就应该可以工作。

即使您使用反射来查看实际使用的程序集版本,您也会发现许多包作者不会在发布之间更改程序集版本。这是为了避免在经典 .NET Framework 项目中绑定重定向的需要,因为所有版本都相同,并且 NuGet 将根据使用项目的已解析包版本选择正确的 DLL。同样,只要没有重大变化,这就是好事。

您可以用来支持不同软件包的一种模式是提供许多“平台”软件包供消费者选择。然后,特定于平台的包将引用具有可共享逻辑的公共包。

那么“平台”将是例如引用“MyLogic.Common”的“MyLogic.XUnit”或“MyLogic.NUnit”(假设测试助手作为示例)