我一直在使用.NET CLR一段时间了,我选择的语言是C#。
直到最近,我还没有意识到C ++ / CLI可以生成能够运行本机代码和托管代码的“混合模式”可执行文件。
现在知道这一点,我的另一位开发人员朋友正在讨论这个属性,并试图确定这种能力何时以及如何有用。
我认为原生代码的功能比托管代码更高效,更强大,但需要额外的开发时间。
过去,我使用严格的原生C ++代码库,并使用Interop来利用我写入本机库的功能。
我可以看到不需要额外库的好处,但我很好奇使用C ++ / CLI在C#中创建的soley托管可执行文件的所有优点/缺点,或使用Interop调用的可执行文件纯粹的原生C ++库?
(旁注:Interop / PInvoke这两个术语是否可以互换,因为我不理解术语之间的区别,只是看到它们使用相同的方式。)
答案 0 :(得分:13)
使用C ++ / CLI,您可以广泛地创建三种类型的对象:
您可能会认为(3)就像使用PInvoke代码编写C#代码来访问本机内容 - 除了为您生成所有PInvoke内容。
当然还有更多内容,以及一些注意事项 - 但这应该可以让您了解它的用途。
换句话说,它真的是一种粘合语言。虽然您可以在C ++ / CLI中编写完全成熟的应用程序,但将托管和本机部分分开并使用C ++ / CLI将这两个部分比使用PInvoke更清晰地连接起来更为正常。
另一个常见用途是使用.Net库调用扩展和现有的本机C ++代码库。
请注意您对代码进行分区,因为在将纯C ++代码透明地编译为IL时,它可能会非常微妙!
至于你的旁注:PInvoke是一种特殊类型的Interop。 Interop也有其他形式,例如COM Interop。事实上,更准确地说,PInvoke是一组语言功能,使Interop与本机代码更容易。
答案 1 :(得分:3)
我过去曾经有效地使用过托管C ++(.NET 1.1前身为C ++ / CLI)。当您希望在托管代码中使用本机C或C ++库时,我发现它最有效。您可以使用整个Interop / PInvoke路由,这会产生一些丑陋的C#代码并经常出现编组问题,或者您可以编写一个托管C ++包装器,这是C ++ / CLI真正发挥作用的地方。
因为C ++ / CLI是托管代码,所以可以通过添加对.DLL的引用,以正常方式从C#(或者如果你倾向于使用VB.NET)调用它。没有编组,没有dllimport,没有像这样的傻瓜。只是正常的项目参考。此外,如果您的本机库是如此设计的,那么您将获得静态链接库的好处,这是一件好事(tm)。
答案 2 :(得分:2)
Phil Nash确实击中了大事。这是我不止一次打过的另一个,也是我过去使用过C ++ / CLI的主要原因:
某些应用程序通过检查某些位置的所有DLL来扩展,以便为具有特定名称的导出函数。在C#中,没有办法声明本机C风格的导出,但您可以在C ++ / CLI中。我在C ++ / CLI中创建了一个“包装器”,它导出该方法,处理C结构到托管对象的任何转换,并将调用传递给用C#编写的程序集。
答案 3 :(得分:1)
某些类型的其他语言无法使用,例如模板, const和跟踪盒装值类型的句柄。
模板专门用于编译时。泛型在运行时是专门的。虽然CLR应该缓存泛型专业化以供将来使用(因此每次使用时都会得到相同的List),但每次请求泛型专业化时仍会有性能损失。
我知道其他语言会丢弃const属性,但是在C ++代码中进行编译时检查总比没有好。
具有类似int ^的类型允许您访问托管堆目录上的内存,而无需进行不必要的拆箱。当将盒装值的跟踪句柄传递给期望跟踪句柄的函数(例如Console :: WriteLine(Object ^))时,这可以帮助提高性能。当然,早期的拳击初始化是无法避免的。在其他语言中,您可以将引用存储在Object变量中并传递它以避免取消装箱,但是您将丢失编译时类型检查。