问题描述
我希望我的库能够处理一系列版本的 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.
- 是否可以通过这种方式实现对多个版本的支持,使用外部命名空间别名和代理?
- 如果是,如何添加对多个版本的 NuGet 包的引用并在代码中使用它们?
- 如果不是,那么正确的做法是什么?
背景
我正在开发用于格式化控制台输出的 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包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!