当前位置:  开发笔记 > 数据库 > 正文

鉴于选择,混合模式程序集与单独的互操作DLL的优缺点是什么?

如何解决《鉴于选择,混合模式程序集与单独的互操作DLL的优缺点是什么?》经验,为你挑选了1个好方法。

当"混合模式组装"和"单独的互操作dll"版本都提供第三方组件时,每种组件的优缺点是什么?

一个很好的例子是System.Data.SQLite.

以上链接有这样的说法:

只有在出于某种原因必须将汇编二进制文件部署到全局程序集缓存的情况下,才应使用[混合模式汇编]程序包.

但为什么?混合模式程序集似乎在我的项目中工作正常,没有安装GAC(只需xcopy到应用程序的exe目录).有一个更少的DLL是很好的.这感觉整洁.那么缺点是什么?

反之亦然,为什么一个人会赞成这两个DLL"native-dll + interop-dll"版本?



1> Lucas Trzesn..:

免责声明:要获得明确的答案,您必须向开发团队的某个人询问,但这是我最好的猜测.

在标准配置中,托管程序集将尝试查找并加载所需的本机DLL.它将在依赖于平台的目录(x86x64)中进行搜索.然后它将加载它在那里找到的DLL并继续向它抛出P/Invoke互操作.

这是与.NET中的本机库进行互操作的一个相当标准的过程 - 唯一的自定义 System.Data.SQLite代码是试图找到DLL并加载正确版本的代码.其余的是普通的P/Invoke.但是,当你处理库时,这甚至是常见的做法.

这种方法的主要优点是库用户可以为AnyCPU平台构建他的项目,并且处理器体系结构将在运行时解析 - 如果你在x86或x64上运行,一切都将按预期工作,前提是两个本机DLL都可用.并且库作者获得的支持请求较少.


让我们将它与混合模式方法进行比较.混合模式DLL有一些缺点,主要的缺点是它必须是特定于平台的.因此,如果您选择此方法,则必须将应用程序绑定到特定平台.如果要同时支持x86和x64,则必须构建单独的版本,每个版本都链接到正确版本的System.Data.SQLite.

如果你没有完全正确,那么繁荣.更糟糕的是,如果你在x64开发机器上为AnyCPU平台构建它,乍一看似乎没问题,但它会在你客户的旧x86机箱上内爆.必须处理这类问题并不好,使用单独的DLL的简单解决方案完全解决了这个问题.

我能想到的另一个缺点是无法从内存加载程序集,但这最多只是一个小小的不便,因为这也适用于本机DLL.

至于GAC,我的猜测是,在单独的本机程序集的情况下,搜索它们的代码在某些情况下可能无法找到它们,或者它可能找到不同版本的DLL.System.Data.SQLite中的代码尝试很难找到本机DLL,但首先没有混合模式DLL的问题,所以失败不是一个选项.


不过,你说:

感觉整洁.

让我们仔细看看这个.:)

System.Data.SQLite 对混合模式互操作有一种非同寻常的方法.通常,您使用C++/CLI构建混合模式程序集.这使您可以将来自同一 C++/CLI项目的托管代码和本机代码组合到一个DLL中,并使用所谓的C++ Interop来处理从托管/非托管屏障的一端到另一端的调用.这样做的好处是它比P/Invoke更轻更快,因为它可以避免大部分编组.

System.Data.SQLite做了一些不同的事情:它将C#代码构建到netmodule中,然后使用C++链接器将netmodule与本机SQLite代码链接起来.这导致混合模式组装.

有趣的是,在使用C++/CLI时,C#没有直接机制来调用同一混合模式程序集中的本机代码,因为C#并不是真正打算在混合模式程序集中使用.因此,来自此最终程序集的C#代码将简单地P/Invoke自身.是的,你没有看错.这还是觉得整洁吗?不过,这是一个聪明的黑客.:)

看看下面的代码UnsafeNativeMethods.cs:

#if PLATFORM_COMPACTFRAMEWORK
    //
    // NOTE: On the .NET Compact Framework, the native interop assembly must
    //       be used because it provides several workarounds to .NET Compact
    //       Framework limitations important for proper operation of the core
    //       System.Data.SQLite functionality (e.g. being able to bind
    //       parameters and handle column values of types Int64 and Double).
    //
    internal const string SQLITE_DLL = "SQLite.Interop.099.dll";
#elif SQLITE_STANDARD
    //
    // NOTE: Otherwise, if the standard SQLite library is enabled, use it.
    //
    internal const string SQLITE_DLL = "sqlite3";
#elif USE_INTEROP_DLL
      //
    // NOTE: Otherwise, if the native SQLite interop assembly is enabled,
    //       use it.
    //
    internal const string SQLITE_DLL = "SQLite.Interop.dll";
#else
    //
    // NOTE: Finally, assume that the mixed-mode assembly is being used.
    //
    internal const string SQLITE_DLL = "System.Data.SQLite.dll";
#endif

如果您想查看构建过程,请查看C++ MSBuild项目.以下是一些链接器选项,显示了netmodules(in )的使用:


  $(INTEROP_ASSEMBLY_RESOURCES) %(AdditionalOptions)
  $(INTEROP_LIBRARY_DIRECTORIES)
  $(ProjectDir)..\bin\$(ConfigurationYear)\$(Configuration)Module\bin\System.Data.SQLite.netmodule $(INTEROP_LIBRARY_DEPENDENCIES);%(AdditionalDependencies)
  $(INTEROP_LINKER_VERSION)
  true
  true
  true
  Windows
  true
  true
  UseLinkTimeCodeGeneration
  MachineX64
  true
  $(INTEROP_KEY_FILE)
  true

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有