0

假设 2 年前,我编写了一个 .NET 类库,比如mylib.dll,它严重依赖于一个外部库,比如foo.dll,它是开源的、MIT 许可的(这是相关的,请继续阅读)。

许多客户使用我的库以及它的依赖程序集。包裹mylib.dllfoo.dll.

日子一天天过去,创建者foo.dll破坏了他们的 API,现在他们部署了一个新版本的库。这个新版本包含了旧版本中包含的大部分类型,但其中一些方法丢失或更改。

问题

一些潜在的消费者已经foo.dll在他们的应用程序中使用它的新版本,供他们自己使用。当我提供它们时mylib.dll,他们不能使用它。他们甚至无法成功构建,因为mylib.dll想要旧版本的foo.dll旧方法和签名。

如何克服这个问题?

我想要一个前向兼容的解决方案,这样就不会再次提出这个问题。所以我想了几件事:

  1. 更新我的源代码以使用新版本的foo.dll. 但这需要大量的工作和时间。此外,这不是向前兼容的,因为有一天这个问题可能会再次出现。
  2. 由于我有确切版本的来源foo.dll,也许我可以轻松更改其名称空间并重建整个事物。这样我就可以享受我自己的版本了foo.dll,这是合法的,因为它的许可证是 MIT。我可以命名修改后的程序集mylib.foo.dll或类似的名称。我什至可以将整个东西合并ILMerge到类似mylib.merged.dll.
  3. 重新设计mylib.dll,以便将所需的功能foo.dll分离为接口和实现。在工程方面,这是最优雅的解决方案。就时间而言,这是一场灾难,因此不能被视为真正的解决方案。

我的问题

为了完成上面的#2,有没有一种改变给定源代码命名空间的捷径?

4

2 回答 2

0

啊哈!是的 - 这是流行的开源库(如 nlog、newtonsoft 等)的消费者的常见痛苦。

1. 允许多个 FOO.DLL(s)

您的问题源于您的输出目录只能包含 DLL 的一份副本(因为所有版本共享相同的文件名)。一些产品将版本号放入 DLL 文件名来解决这个问题——但我认为这很难看。您可以使用程序集绑定重定向将您的 DLL 依赖项存储在 bin/子文件夹中以防止覆盖 - 但这有点像以下解决方案更好地解决的 hack...

2. 合并

对于您的客户来说,最简单的解决方案是将您的程序集及其依赖项打包到一个多模块 DLL 中 - 即使用ILMerge 将foo.dll 合并到您的 mylib.dll 中(是的,一个 DLL 可以包含多个程序集) - 然后您的product 似乎没有依赖项(实际上并非如此,它的依赖项只是在一个 DLL 中提供!太好了!)。

这是一个比尝试重新编译 foo.dll 或命名空间搜索/替换更好的解决方案,因为您不必弄乱依赖源代码并冒着破坏它的风险......而且一旦您开始更改第 3 方源代码,您必须维护这些更改-当他们发布新版本时...在这里您再次搜索/替换...

问题解决了。

警告:请记住,如果您的 mylib.dll 将 foo.dll 中声明的类型返回给调用程序(您客户的程序),他们可能会收到一个类转换异常,因为他们的 DLL 需要不同版本的类型。因此,仅当您对 foo.dll 的依赖是黑盒(未公开)时,才建议使用此解决方案。但是,我希望这对您来说不是问题,或者您不会考虑将 FOO 类型移动到不同的命名空间中。

于 2013-04-10T21:58:22.163 回答
0

如果您不使用新方法中foo.dll缺少的许多旧方法,一个可行的解决方案可能是将您的代码链接到新方法foo.dll,并制作mylib.foo.legacy.dll包含缺失功能的类似内容,您可以从旧方法中复制foo源代码,因为它是开源的并且获得了 MIT 许可。

无论您做什么,以最新版本foo.dll为基础,作者都不太可能回到旧功能。如果您使用该属性标记从旧 dll 复制的遗留方法[obsolete],您将收到编译警告,显示仍然引用旧函数的位置。然后,随着时间的推移,您可以努力删除这些引用,直到可以完全删除旧版 dll。

于 2013-04-10T08:18:34.700 回答