如果有选择,混合模式程序集与单独的互操作 DLL 的优缺点是什么? [英] Given the choice, what are the pros/cons of mixed-mode assemblies vs. separate interop DLLs?

查看:38
本文介绍了如果有选择,混合模式程序集与单独的互操作 DLL 的优缺点是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当在混合模式程序集"和单独的互操作 dll"版本中都提供 3rd 方组件时,每个版本的优缺点是什么?

When a 3rd-party component is offered in both "mixed-mode assembly" and "separate interop dll" versions, what are the pros and cons of each?

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

上面的链接是这样说的:

The above link has this to say:

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

[Mixed-mode assembly] packages should only be used in cases where the assembly binary must be deployed to the Global Assembly Cache for some reason.

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

But WHY? The mixed-mode assembly seems to work just fine in my projects, with no GAC installation (just xcopy to the application's exe directory). It's nice to have one less DLL. It feels tidier. So what are the cons?

反之亦然,为什么人们会/应该喜欢两个 DLL 的native-dll + interop-dll"版本?

Vice-versa, why would/should one ever favor the two-DLL "native-dll + interop-dll" version?

推荐答案

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

Disclaimer: For a definite answer, you'd have to ask someone from the development team, but here's my best guess.

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

In the standard configuration, the managed assembly will try to locate and load the native DLL it needs. It will search in the platform-dependent directories (x86 or x64). It will then load the DLL it found there and proceed to throw P/Invoke interop at it.

这是与 .NET 中的本机库进行互操作的相当标准的过程 - 唯一的自定义 System.Data.SQLite 代码是尝试定位 DLL 并加载正确版本的代码.其余的是普通的 P/Invoke.但即使是在处理图书馆时,这也是司空见惯的做法.

This is a fairly standard procedure for interoperating with native libraries in .NET - the only custom System.Data.SQLite code is the one that tries to locate the DLL and loads the right version. The rest is plain P/Invoke. But even this is commonplace practice when you deal with libraries.

这种方法的主要优点是库用户可以为AnyCPU平台构建他的项目,并且处理器架构将在运行时解决 - 一切都会正常进行正如预期的那样,您应该在 x86 或 x64 上运行,前提是这两个本机 DLL 都可用.图书馆作者获得的支持请求更少.

The major advantage of this approach is that the library user can build his project for the AnyCPU platform, and the processor architecture will be resolved at runtime - everything will work as expected, should you run on x86 or x64, provided both native DLLs are available. And the library author gets less support requests.

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

Let's compare it with the mixed-mode approach. A mixed-mode DLL has a few disadvantages, the major one being it must be platform-specific. So if you choose this approach, you'll have to tie your application to a particular platform. If you want to support both x86 and x64, you'll have to build separate versions, each one linking to the correct version of System.Data.SQLite.

如果你没有完全正确地做到这一点,那么繁荣.更糟糕的是,如果您在 x64 开发机器上为 AnyCPU 平台构建它,乍一看它似乎工作正常,但它会在您客户的旧 x86 机器上崩溃.不得不处理这类问题并不好,使用单独的 DLL 的简单解决方案完全解决了问题.

If you don't get this perfectly right, then boom. Worse, if you build it for the AnyCPU platform on your x64 development machine, it will seem to work alright at first glance, but it will implode on your customer's old x86 box. Having to deal with this kind of issues isn't nice, and the simple solution of using separate DLLs solves the problem entirely.

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

The other disadvantage I can think of is the inability to load the assembly from memory, but this should be at most a minor inconvenience, since this applies to native DLLs too.

对于 GAC,我的猜测是,在单独的本机程序集的情况下,搜索它们的代码在某些情况下可能无法定位它们,或者它可能定位到不同版本的 DLL.System.Data.SQLite 中的代码非常努力地尝试定位本机 DLL,但首先混合模式 DLL 没有这样的问题,因此失败不是一种选择.

As for the GAC, my guess would be that in the case of separate native assemblies, the code which searches for them could fail to locate them in some cases, or it could locate a different version of the DLL. The code in System.Data.SQLite tries really hard to locate the native DLL, but there's no such problem with the mixed-mode DLL in the first place, so failure is not an option.

尽管如此,你说:

感觉更整洁.

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

Let's take a closer look at this. :)

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

System.Data.SQLite has quite an unusual approach to mixed-mode interop. Usually, you'd use C++/CLI to build a mixed-mode assembly. This lets you combine managed and native code from the same C++/CLI project into a single DLL and uses the so-called C++ Interop to deal with calls from the one to the other side of the managed/unmanaged barrier. The advantage of this is that it's lighter and faster than P/Invoke, as it can avoid most of the marshaling.

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

System.Data.SQLite does something different: it builds its C# code into a netmodule, and then uses the C++ linker to link the netmodule with the native SQLite code. This results in a mixed-mode assembly.

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

The interesting thing is that, unline C++/CLI, C# has no direct mechanism to invoke native code in the same mixed-mode assembly, as C# wasn't really intended to be used in mixed-mode assemblies in the first place. So, the C# code from this final assembly will simply P/Invoke itself. Yes, you read that right. Does this still feel as tidy? Nevertheless, it's a clever hack. :)

看一下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 项目.以下是一些显示使用网络模块的链接器选项(在 中):

If you'd like to see the build process, take a look at the C++ MSBuild projects. Here are some linker options showing the use of netmodules (in <AdditionalDependencies>):

<Link>
  <AdditionalOptions>$(INTEROP_ASSEMBLY_RESOURCES) %(AdditionalOptions)</AdditionalOptions>
  <AdditionalLibraryDirectories>$(INTEROP_LIBRARY_DIRECTORIES)</AdditionalLibraryDirectories>
  <AdditionalDependencies>$(ProjectDir)..in$(ConfigurationYear)$(Configuration)ModuleinSystem.Data.SQLite.netmodule $(INTEROP_LIBRARY_DEPENDENCIES);%(AdditionalDependencies)</AdditionalDependencies>
  <Version>$(INTEROP_LINKER_VERSION)</Version>
  <GenerateDebugInformation>true</GenerateDebugInformation>
  <GenerateMapFile>true</GenerateMapFile>
  <MapExports>true</MapExports>
  <SubSystem>Windows</SubSystem>
  <OptimizeReferences>true</OptimizeReferences>
  <EnableCOMDATFolding>true</EnableCOMDATFolding>
  <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
  <TargetMachine>MachineX64</TargetMachine>
  <CLRUnmanagedCodeCheck>true</CLRUnmanagedCodeCheck>
  <KeyFile>$(INTEROP_KEY_FILE)</KeyFile>
  <DelaySign>true</DelaySign>
</Link>

这篇关于如果有选择,混合模式程序集与单独的互操作 DLL 的优缺点是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆