一个库/NuGet包支持多个版本的NuGet包 [英] Supporting multiple versions of NuGet package in one library / NuGet package

查看:44
本文介绍了一个库/NuGet包支持多个版本的NuGet包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want my library to work with a range of versions of a NuGet package with breaking changes in API between the changes. I haven't investigated it further, but this path looks promising:

  • 通过指定 外部命名空间别名.
  • 为所需的类创建代理,使用标志/异常/任何东西来说明实际支持的内容.
  • 在运行时根据实际加载到应用程序中的版本选择正确的代理.
  • 不会调用依赖于不存在 API 的代码,因此一切正常.

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

While this may seem complicated, it has many benefits over a more straightforward approach of supporting every version in a separate assembly:

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

但是,目前还不清楚这是否可能.甚至在使用代理和检测当前版本之前,我都坚持基础知识.

However, it's unclear whether it's possible at all. Even before getting to proxies and detecting current version, I'm stuck with the basics.

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

I can't even add multiple PackageReference nodes to my .csproj, only one reference actually works. There's a workaround for adding extern aliases which aren't supported by NuGet directly, but I can't get to that point because I can't get two references. And if I somehow get two, I won't be able to tell them apart.

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

背景

我正在开发用于格式化控制台输出的 CsConsoleFormat 库.我想直接支持流行命令行包的所有相关版本,这样无论使用什么命令行解析库,几乎不需要编码就可以添加漂亮的命令行帮助和类似的东西.

Background

I'm working on CsConsoleFormat library for formatting Console output. I want to support all relevant versions of popular command-line packages directly, so that pretty command line help and stuff like this could be added with almost no coding, no matter what command line parsing library is used.

我想声明我只支持最新版本"在我的情况下是可以接受的,但我宁愿获得更广泛的支持,即使它更复杂.理想情况下,我想要一个 NuGet 包,它声明依赖于受支持的最低版本,但支持最新版本的所有内容.

I guess declaring "I support only the latest version" is somewhat acceptable in my case, but I'd rather have wider support even if it's more complicated. Ideally, I want a NuGet package which declares dependency on the lowest supported version, but supports everything up to the latest version.

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

I kinda got it to work, but with many issues. See issue on GitHub NuGet Home for more details.

推荐答案

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

If you insist on extern aliases - you can add multiple version references directly, as dll file, not as nuget package.

假设我想依赖 Newtonsoft.Json 包版本 10.0.3+.但是,如果用户安装了版本 11 - 我想使用仅在此版本 (11) 中可用的通用 JsonConverter<T> 类.那么我的 csproj 可能是这样的:

Suppose I want to take a dependency on Newtonsoft.Json package version 10.0.3+. However if user has version 11 installed - I want to use generic JsonConverter<T> class available only in this version (11). Then my csproj might look like this:

<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(使用全局、非别名命名空间):

And two implementations, v10 (uses global, non-aliased namespace):

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 版本创建序列化程序的工厂:

And finally factory which creates serializer depending on current available json.net version:

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 - 它将使用此版本中可用的功能.

Now if I pack this as nuget - it will have single dependency on Newtonsoft.Json version 10.0.3 and that's all. However, if user installs Newtonsoft.Json of version 11 - it will use capabilities available in this version.

缺点:

  • Visual Studio Resharper intellisense 有时不喜欢这种方法,并在实际上一切编译正常时显示 intellisense 错误.

  • Visual Studio Resharper intellisense doesn't like this approach sometimes and shows intellisense errors when in reality everything compiles just fine.

编译时可能会出现版本冲突"警告.

You might have "version conflict" warnings on compilation.

这篇关于一个库/NuGet包支持多个版本的NuGet包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆