是否可以用“弱”名称替换对强名称程序集的引用?参考?
我正在编写一个需要 SQL Server SMO 库的 .NET 工具。我不在乎它是来自 Server 2005 (9.0)、2008 (10.0) 还是 2008 R2 的版本(可能是 10.5,没有检查)。 SMO 库与 SQL Server 一起安装,因此我可以放心地假设在安装了 SQL Server 的任何系统上,也可以使用某些版本的 SMO 库。
不幸的是,SMO 库具有强名称:如果我在项目中添加对 SMO 9.0 的引用,并且客户系统上仅存在 SMO 10.0,则它将失败 (FileNotFoundException
),反之亦然。
是否有某种方法可以告诉编译器任何版本的库都适合我?或者我真的必须分发 3 个相同版本的工具,每个版本都编译为SMO 的不同版本?
免责声明:我确实知道 SMO 库(以及 SMO 库所需的库)可以重新分发。但是 (a) 一个纤薄的 100KB 独立 EXE 和 (b) 安装了一大堆先决条件的完整安装包之间存在很大差异。
免责声明 2:我知道以下重复内容:
但是,提供的解决方案不适合。在问题 1 中,开发人员可以控制引用的 DLL(我没有);在问题 2 中,开发人员可以控制目标系统(我也没有)。
I'm writing a .NET tool that requires the SQL Server SMO library. I don't care if it's the version from Server 2005 (9.0), 2008 (10.0) or 2008 R2 (probably 10.5, didn't check). The SMO library is installed together SQL Server, so I can safely assume that on any system with SQL Server installed, some version of the SMO library is available as well.
Unfortunately, the SMO libraries are strongly-named: If I add a reference to SMO 9.0 in my project, it will fail (FileNotFoundException
) if only SMO 10.0 is present on the customer's system, and vice versa.
Is there some way to tell the compiler that any version of the library is fine for me? Or do I really have to distribute 3 identical versions of my tool, each compiled to a different version of the SMO?
Disclaimer: I do know that the SMO libraries (and the libraries required by the SMO libraries) can be redistributed. But there's a big difference between (a) one slim 100KB standalone EXE and (b) a full-blown setup package that installs a whole bunch of prerequisites.
Disclaimer 2: I am aware of the following duplicates:
- c# - can you make a “weak” assembly reference to a strong named assembly
- Need a C# Assembly to reference a strongly named assembly loosely
The solutions provided do not fit, however. In question 1, the developer has control over the referenced DLL (which I do not); in question 2, the developer has control over the target systems (which I do not either).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
据我所知,不可能消除对确切版本的依赖。这就是强名称存在的原因之一——避免版本不匹配。程序集的内部结构甚至公共接口可能会在版本之间发生变化,您会发现新版本不向后兼容旧版本。因此,.NET 会查找编译期间使用的版本,以确保应用程序正常工作。
如果第三方确定其新版本向后兼容,并且将程序集部署到 GAC,则可以添加
如果您决定要强制加载另一个程序集,您可以使用@chibacity提到的方法或为
AppDomain.CurrentDomain.AssemblyResolve
实现处理程序。当 .NET 无法找到引用的程序集时,会触发此事件,您可以实现自己的逻辑来查找它并通过调用Assembly.LoadFrom
加载它。在这种情况下,加载哪个版本完全取决于您。As I know it is not possible to remove the dependency on exact version. That is one of reasons why strong names exist - to avoid version mismatch. Internals or even public interfaces of the assembly can change among version and you can find that new version is not backward compatible with the old one. Because of that .NET looks for version used during compilation to make sure that application works correctly.
If third party decides that their new version is backward compatible and if they deploy assembly to GAC they can add publisher policy which will do redirect automatically.
If you decide that you want to force loading another assembly you can use the approach mentioned by @chibacity or implement handler for
AppDomain.CurrentDomain.AssemblyResolve
. This event fires when .NET is not able to find referenced assembly and you can implement your own logic to find it and load it by callingAssembly.LoadFrom
. In such case it is completely up to you which version you load.您可以使用程序集绑定重定向。
例如:
更新
我从你的评论中看到我们必须稍微反向思考这个问题。
我做了一些实验,其中我针对程序集的版本进行编译:4.0.0.0,但希望确保它会加载该版本以及一些选定的旧版本。通过这种方式,您不依赖于任何单个版本,而是依赖于您已配置的任何版本。
如果系统上有以下任何版本,以下命令将确保加载
VersionedAssembly
:4.0.0.0、3.0.0.0、2.0.0.0、1.0.0.0。You can use Assembly Binding Redirection.
For example:
Update
I see from your comment that we have to think about this in reverse a little.
I did some experiments where I compiled against a version of an assembly: 4.0.0.0, but wanted to make sure it would load that version, plus some selected older versions. In this way you are not dependent on any single version but against any of the versions you have configured.
The following will ensure that
VersionedAssembly
will be loaded if any of the following versions are on the system: 4.0.0.0, 3.0.0.0, 2.0.0.0, 1.0.0.0.根据Ladislav的建议重写
AssemblyResolve
,我能够提出以下解决方案:注意:直接在 AssemblyResolve 事件处理程序中使用 Assembly.Load 不是一个好主意,因为如果 Load 失败,它会递归调用事件处理程序。
Based on Ladislav's suggestion of overriding
AssemblyResolve
, I was able to come up with the following solution:Note: Using Assembly.Load directly in the AssemblyResolve event handler is not a good idea, since it recursively calls the event handler if Load fails.