非托管C#代码是否编译成IL并在CLR上运行?

时间:2012-09-12 13:47:28

标签: c# clr unmanaged

在询问manually managing CLR memory时,我意识到自己知之甚少。

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

我希望在托管上下文之外的C#中使用我的应用程序的整个写层来管理较低级别的数据。然后,我想从托管图层访问此图层。

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

2 个答案:

答案 0 :(得分:14)

我认为这与你在问题中提到的同一个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代码。这相对较快,但在代码中看起来有点难看(加上很难维护/测试)(good article with C#/C/Assembly samples
  • 一种慢得多的方法,但对其他语言更开放:Web服务(SOAP,WS,REST和公司),排队(如MSMQ,NServiceBus等),也(可能)进程间通信。因此,非托管进程位于一端,托管应用程序位于另一端。

答案 1 :(得分:1)

我知道这是一个C#问题,但如果您对C ++感到满意, C ++ / CLI 可能是一个值得考虑的选择。

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

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

请参阅此question,了解有关如何完成的一些信息。