在32位和64位C#世界中使用System.Data.SQLite的选项

我理解为什么在32位和64位版本中提供System.Data.SQLite.dll。 所以我们不要再纠缠于此并继续前进。 🙂

由于它以这种方式完成,它似乎使得纯粹的C#开发更难以做出3个选择。

  1. 是仅支持32位并强制使用托管程序集来编译x86并在32或64位运行时处理它,并且当你在64位环境中时会失去优势。

  2. 是强制64位并且仅支持64位并且失去了在32位上运行的能力但是获得了64位的所有优点。

  3. 是创建两个版本的程序集,一个编译x86并使用32位SQLite,另一个编译x64并使用64位SQLite。 它阻止使用“ANY”作为编译选项,并且能够轻松地将单个构建部署到任一类型。 从发展的角度来管理并不是那么可怕,因为我们需要两个项目。 只将C#代码正式放在一个,而另一个只使用“链接”到另一个代码。 这仅用于编译目的。 仍然让我们必须管理两个输出以进行部署。

尽管如此,我只是在寻找确认以上是唯一正确的选择。

但是,如果我有其他选择,请告诉我。 具体来说,如果有一种方法可以获得一个可以编译为ANY的C#DLL,那么它可以利用32位或64位,具体取决于它的运行位置,仍然使用System.Data.SQLite.dll。

将您的主要应用程序保存在AnyCPU有两种常用的解决方案:

  • 将x86和x64程序集安装到GAC中:它们可以(应该!)具有相同的程序集名称,GAC将自动决定是使用x86还是x64版本。

  • 使用Assembly.LoadFrom挂钩到AppDomain.AssemblyResolve并从子目录提供正确的程序集

这是对Springy76答案的详细阐述。 做这个:

public class AssemblyResolver { public static void HandleUnresovledAssemblies() { AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += currentDomain_AssemblyResolve; } private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { if (args.Name == "System.Data.SQLite") { var path = Path.Combine(pathToWhereYourNativeFolderLives, "Native"); if (IntPtr.Size == 8) // or for .NET4 use Environment.Is64BitProcess { path = Path.Combine(path, "64"); } else { path = Path.Combine(path, "32"); } path = Path.Combine(path, "System.Data.SQLite.DLL"); Assembly assembly = Assembly.LoadFrom(path); return assembly; } return null; } } 

确保生成的路径指向32位或64位SQLite Dll的正确位置。 就个人而言,我在这个NuGet包中有很好的结果: http ://www.nuget.org/packages/SQLitex64

(您只需要使用NuGet包来获取已编译的SQLite Dll。一旦获得它们,删除由NuGet和NuGet包本身创建的项目中对SQLite的引用。实际上,保留引用可以干扰此解决方案,因为SQLite永远不会被识别为未解析的程序集。)

尽可能早地调用’HandleUnresolvedAssemblies()’,最好是在任何Bootstrapping期间。

Oracle的ODP.NET与本机32/64位OCI DLL相似也存在类似的问题。

我们通过为我们的项目创建’x86’和’x64’平台来解决它,然后手动编辑我们的项目文件以使用条件引用:

     False ..\ThirdParty\ODP.NET\x64\Oracle.DataAccess.dll   oci.dll PreserveNewest   orannzsbb11.dll PreserveNewest   oraociei11.dll PreserveNewest   OraOps11w.dll PreserveNewest       False ..\ThirdParty\ODP.NET\x86\Oracle.DataAccess.dll   oci.dll PreserveNewest   orannzsbb11.dll PreserveNewest   oraociei11.dll PreserveNewest   OraOps11w.dll PreserveNewest     

这使我们能够避免使用2个不同的项目。 我相信你可以为SQLite做类似的事情。

从发展的角度来管理并不是那么可怕,因为我们需要两个项目。

事实并非如此 – 您可以在同一个项目中使用两个构建配置。 在部署时,您需要为x86和x64构建,但代码库和项目可以是相同的。

我目前在一个更大的生产项目中执行此操作,既由SQLite提供,也包括其他包含x64和x86变体的本机/互操作库。

除非您的应用程序需要超过4GB的内存,否则通常选择一种方法。 请记住,64位操作系统上的32位应用程序具有64位的大部分优点,没有许多缺点。 这就是为什么x86是VS 2010中.exe应用程序的默认目标。

Branko Dimitrijevic说:“我确信你可以为SQLite做类似的事情。” 这是正确的。 🙂

遇到同样的问题,我找到了罗德尼的问题和布兰科的答案,并亲自尝试过。 对于任何想要查看我的SQLite实现的人,请转到:

     False System.Data.SQLite\x64\System.Data.SQLite.dll       False System.Data.SQLite\x86\System.Data.SQLite.dll                

当然,您可以将HintPath命名为您喜欢的任何名称。

我发现这是一个完美的解决方案:我可以维护一个项目,并根据需要在目标平台之间快速切换。 唯一可能的缺点是我无法在解决方案资源管理器中看到参考。 但这是为整体function付出的小代价。

您还可以通过更改Visual Studio中的编译选项来解决此问题:

要在Visual Studio中更改编译设置:

  1. 转到程序的启动项目。
  2. 打开属性窗口。
  3. 单击编译选项卡。
  4. 单击高级编译选项。
  5. 将目标CPU选项更改为x86。

您的程序现在将始终以32位模式运行,即使在64位计算机上运行也是如此。

您还可以提供两个分发,一个针对上面提到的每个环境。 虽然这将成为未来的标准,但对于我目前的项目来说,这是最好和最简单的选择。