让我们假设2年前,我写了一个.NET类库,比如mylib.dll
,它很大程度上取决于外部库,比如foo.dll
,它是开源的,MIT许可的(相关的) ,请继续阅读。
许多客户使用我的库及其依赖程序集。该软件包为mylib.dll
foo.dll
。
几天过去了,foo.dll
的创建者破坏了他们的API,现在他们部署了新版本的库。此新版本包含旧版本中包含的大多数类型,但某些方法已丢失或更改。
一些潜在消费者已经在其应用程序中使用foo.dll
新版本,以供自己使用。当我提供mylib.dll
时,他们无法使用它。他们甚至无法成功构建,因为mylib.dll
希望旧版本的foo.dll
具有旧方法和签名。
我想要一个前向兼容的解决方案,以便不再提出此问题。所以我想了几件事:
foo.dll
。但这需要大量的工作和时间。此外,这不是向前兼容的,因为有一天可能会再次提出此问题。foo.dll
的确切版本的来源,或许我可以轻松地更改其命名空间并重建整个事物。通过这种方式,我可以享受我自己的foo.dll
版本,这是合法的,因为它的许可是麻省理工学院。我可以命名修改后的程序集mylib.foo.dll
或类似的东西。我甚至可以使用ILMerge
将整个内容合并到mylib.merged.dll
。mylib.dll
,以便将foo.dll
所需的功能分为界面和实现。在工程方面,这是最优雅的解决方案。就时间而言,这是一场灾难,因此不能被视为真正的解决方案。要完成上面的#2,是否有一种简短的方法来更改给定源代码的命名空间?
答案 0 :(得分:0)
如果您没有使用新版本中遗漏的旧foo.dll
的许多方法,那么可行的解决方案是将您的代码链接到新的foo.dll
,并制作类似的内容mylib.foo.legacy.dll
包含缺少的功能,您可以从旧的foo
来源复制,因为它的开源和MIT已获得许可。
无论你做什么,以最新版本的foo.dll
为基础,作者都不太可能回到旧功能。如果您使用[obsolete]
属性标记从旧dll复制的旧方法,则会收到编译警告,显示仍旧引用旧函数的位置。然后,您可以随着时间的推移去除这些引用,直到可以完全删除旧版dll。
答案 1 :(得分:0)
啊哈!是的 - 这是流行的开源库的消费者的常见痛苦,如nlog,newtonsoft等等。
<强> 1。允许多个FOO.DLL
您的问题源于您的输出目录只能包含DLL的一个副本(因为所有版本共享相同的文件名)。有些产品将版本号放入DLL文件名中来解决这个问题 - 但我认为这很难看。您可以使用程序集绑定重定向将您的DLL依赖项存储在bin /子文件夹中以防止覆盖 - 但这有点像使用以下解决方案更好地解决了...
<强> 2。 ILMERGE 强>
客户最简单的解决方案是将程序集及其依赖项打包到多模块DLL中 - 即将ILMerge to MERGE foo.dll用于mylib.dll(是的,一个DLL可以包含多个程序集) - 然后你的产品似乎是无依赖的(它不是真的,它的依赖只是在一个DLL中提供!很好!)。
这是一个比尝试重新编译foo.dll或命名空间搜索/替换更好的解决方案,因为你不必弄乱依赖源代码并冒险破解它...加上你开始更改第三方源代码,您必须维护这些更改 - 当他们发布新版本时......在这里您再次搜索/替换...
问题解决了。
警告:请记住,如果您的mylib.dll将foo.dll中声明的类型返回给调用程序(您的客户程序),则它们可能会获得类转换异常,因为它们的DLL期望该类型的不同版本。因此,仅当您对foo.dll的依赖是黑盒(未公开)时,才建议使用此解决方案。但是,我希望这对您来说不是问题,或者您不会考虑将FOO类型移动到不同的命名空间。