免责声明:要获得明确的答案,您必须询问开发团队的人员,但这是我的最佳猜测。
在标准配置中,托管程序集将尝试查找并加载它所需的本机 DLL。它将在依赖于平台的目录中搜索(x86
or x64
)。然后,它将加载在那里找到的 DLL,并继续向其抛出 P/Invoke 互操作。
这是与 .NET 中的本机库互操作的相当标准的过程 - 唯一的customSystem.Data.SQLite 代码是尝试定位 DLL 并加载正确版本的代码。其余的就是简单的 P/Invoke。但即便如此,当你与图书馆打交道时,这也是常见的做法。
The major这种方法的优点是库用户可以为AnyCPU平台,并且处理器架构将在运行时解析 - 如果您在 x86 或 x64 上运行,一切都会按预期工作,前提是两个本机 DLL 都可用。而且库作者得到的支持请求也更少。
让我们将其与混合模式方法进行比较。混合模式 DLL 有一些缺点,其中最主要的是它must特定于平台。因此,如果您选择这种方法,则必须将您的应用程序绑定到特定平台。如果您想同时支持 x86 和 x64,则必须构建单独的版本,每个版本都链接到正确版本的 System.Data.SQLite。
如果你没有完全正确地理解这一点,那么boom。更糟糕的是,如果你构建它是为了AnyCPUx64 开发机器上的平台,它将seem乍一看工作正常,但它会在客户的旧 x86 机器上崩溃。必须处理此类问题并不好,使用单独的 DLL 的简单解决方案可以完全解决该问题。
我能想到的另一个缺点是无法从内存加载程序集,但这最多只是一个小小的不便,因为这也适用于本机 DLL。
至于 GAC,我的猜测是,在单独的本机程序集的情况下,搜索它们的代码在某些情况下可能无法找到它们,或者可能会找到不同版本的 DLL。 System.Data.SQLite 中的代码非常努力地尝试定位本机 DLL,但混合模式 DLL 首先就不存在这样的问题,因此失败不是一种选择。
尽管如此,你还是说:
It feels tidier.
让我们仔细看看这一点。 :)
System.Data.SQLite 有相当多的unusual混合模式互操作方法。通常,您会使用 C++/CLI 来构建混合模式程序集。这使您可以将托管代码和本机代码结合起来sameC++/CLI 项目到单个 DLL 中并使用所谓的C++ 互操作 https://msdn.microsoft.com/en-us/library/ky8kkddw.aspx处理从托管/非托管屏障的一侧到另一侧的调用。这样做的优点是它比 P/Invoke 更轻、更快,因为它可以避免大部分编组。
System.Data.SQLite 做了一些不同的事情:它将其 C# 代码构建成网络模块, 进而使用 C++ 链接器 https://msdn.microsoft.com/en-us/library/k669k83h.aspx链接网络模块与本机 SQLite 代码。这会产生混合模式装配。
有趣的是,unline C++/CLI,C# 没有direct在同一混合模式程序集中调用本机代码的机制,因为 C# 最初并不打算在混合模式程序集中使用。因此,最终程序集中的 C# 代码将简单地P/调用自身。是的,你没有看错。这仍然感觉整洁吗?尽管如此,这是一个聪明的技巧。 :)
看一下中的代码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 项目。以下是一些链接器选项,显示了网络模块的使用(在<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>