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

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

问题描述

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

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

上面的链接说:


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

[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的本地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。它将在平台相关目录( x86 x64 )中搜索。然后它将加载在那里找到的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中的本机库进行互操作的相当标准的过程-唯一的 custom 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.

不要完全正确,然后 boom 。更糟糕的是,如果您在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.

不过,您说:


感觉到了

It feels tidier.

让我们仔细研究一下。 :)

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#代码放入 netmodule 中,然后使用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#没有 direct 机制来调用本机在同一混合模式程序集中编写代码,因为C#最初并没有真正打算在混合模式程序集中使用。因此,此最终程序集中的C#代码将简单地 P /调用自身。是的,你没看错。这样还算整洁吗?不过,这是一个聪明的技巧。 :)

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项目。以下是一些链接器选项,它们显示了netmodule的使用(在< AdditionalDependencies> 中):

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)..\bin\$(ConfigurationYear)\$(Configuration)Module\bin\System.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天全站免登陆