10

在询问手动管理 CLR 内存的过程中,我意识到我知道的很少。

我知道当您退出托管上下文时,CLR 会在堆栈上放置一个“cookie”,这样垃圾收集器就不会占用您的内存空间;但是,在我读过的所有内容中,假设您正在调用一些用 C 编写的库。

我想在托管上下文之外用 C# 编写我的应用程序的整个写入层,以在低级别管理数据。然后,我想从托管层访问该层。

在这种情况下,我的非托管 C# 代码会编译为 IL 并在 CLR 上运行吗?这是如何运作的?

4

2 回答 2

15

我认为这与您在问题中提到的同一个 C# 数据库项目有关。

技​​术上可以用 C/C++ 或任何其他语言实现整个写入层。从技术上讲,在 C# 中拥有所有其他内容是可能的。我目前正在开发一个应用程序,该应用程序将非托管代码用于一些高性能的低级内容,并将 C# 用于业务逻辑和上层管理。

但是,任务的复杂性不容小觑。做到这一点的典型方法是设计一个双方都能理解的合同。合约将暴露给托管语言,托管语言将触发对本机应用程序的调用。如果您曾经尝试过从 C# 调用 C++ 方法,您就会明白……此外,每次调用非托管代码都会产生相当大的性能开销,这可能会扼杀低级性能的整个想法。

如果您真的对高性能关系数据库感兴趣,那么请使用单一的低级语言。

如果您想拥有一个简单但完整的数据库实现,只需使用 C#。除非您完全了解其复杂性,否则请勿混合使用这两种语言。请参阅 Raven DB - 一个基于文档的 NoSQL 数据库,仅完全用 C# 构建。

我的非托管 C# 代码会编译为 IL 并在 CLR 上运行吗?

不,不存在非托管 C# 之类的东西。C# 代码将始终编译为 IL 代码并由 CLR 执行。这是托管代码调用非托管代码的情况。非托管代码可以用多种语言 C/C++/Assembly 等实现,但 CLR 不知道该代码中发生了什么。

从评论更新。有一个工具 (ngen.exe) 可以将 C# 直接编译为本机架构特定的代码。该工具旨在通过删除 JIT 编译阶段并将本机代码直接放入可执行映像或库中来提高托管应用程序的性能。然而,这段代码仍然由 CLR 主机“管理”——内存分配和收集、托管线程、应用程序域、异常处理、安全性和所有其他方面仍然由 CLR 控制。因此,即使 C# 在技术上可以编译为本机代码,该代码也不会作为独立的本机映像运行。

这是如何运作的?

托管代码与非托管代码互操作。有几种方法可以做到这一点:

  • 通过.Net Interop 的代码。这相对较快,但在代码中看起来有点难看(而且很难维护/测试)(C#/C/Assembly 示例的好文章
  • 一种慢得多的方法,但对其他语言更开放:Web wervices(SOAP、WS、REST 和公司)、队列(例如 MSMQ、NServiceBus 等),以及(可能)进程间通信。因此,非托管进程位于一端,托管应用程序位于另一端。
于 2012-09-12T14:02:53.397 回答
1

我知道这是一个 C# 问题,但如果您熟悉 C++,C++/CLI可能是一个值得考虑的选项。

它允许您有选择地将部分 C++ 代码编译为托管或非托管上下文 - 但是请注意,与 CLR 类型交互的代码必须在托管上下文中运行。

我不知道在 C++ 代码中从托管上下文转换到非托管上下文以及从 C++ 代码中转换的运行时成本,但我认为它必须类似于通过 C# 中的 .net Interop 调用本机方法的成本,即正如@oleksii 已经指出的那样,价格昂贵。根据我的经验,如果您需要经常与本机 C 或 C++ 库进行交互,这确实得到了回报 - 恕我直言,从 C++/CLI 项目中调用它们比在 C# 中编写所需的 .net Interop 接口要容易得多。

有关如何完成的一些信息,请参阅此问题。

于 2012-09-12T18:40:00.630 回答