与 C# 相比,使用 C++CLI 的情况或优缺点是什么

发布于 2024-08-13 14:34:01 字数 426 浏览 3 评论 0原文

我已经关注 .NET CLR 一段时间了,我选择的语言是 C#。

直到最近,我还不知道 C++/CLI 可以生成能够运行本机代码和托管代码的“混合模式”可执行文件。

现在知道了这一点,我的另一位开发人员朋友正在讨论此属性,并试图确定此功能何时以及如何有用。

我认为本机代码具有比托管代码更高效、更强大的能力,但代价是额外的开发时间。

过去,我采用严格的本机 C++ 代码库,并使用 Interop 来利用我写入本机库的功能。

我可以看到不需要额外库的好处,但我很好奇使用 C++/CLI 相对于在 C# 中创建的单独托管可执行文件的所有优点/缺点,或者使用 Interop 调用纯本机 C++ 的可执行文件图书馆?

(旁注:术语 Interop/PInvoke 是否可以互换,因为我不理解这些术语之间的区别,只是看到它们以相同的方式使用。)

I have been keeping up with .NET CLR for awhile now, and my language of choice is C#.

Up until recently, I was unaware that C++/CLI could produce "mixed mode" executables capable of running native and managed code.

Now knowing this, another developer friend of mine were discussing this attribute and trying to determine when and how this ability would be useful.

I take it as a given that native code has the capability to be more efficient and powerful than managed code, at the expense of additional development time.

In the past, I resorted to strictly native C++ code libraries and used Interop to make use of the functionality I wrote into the native library.

I can see the benefit of not requiring an additional library, but I'm curious as to what all the pros/cons of using C++/CLI over soley managed executable created in C#, or such an executable using Interop to call a purely native C++ library?

(Sidenote: Are the terms Interop/PInvoke interchangeable, as I d.on't understand the difference between the terms, simply seen them used the same way.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

作业与我同在 2024-08-20 14:34:01

一般来说,使用 C++/CLI 您可以创建三种类型的对象:

  1. 托管类型。这些将编译为与等效 C# 基本相同的 IL。这里没有表演机会。
  2. 原生类型。编译为本机代码,就像直接使用 C++ 一样。
  3. 混合模式类型。它们编译为托管代码,但也允许您引用本机类型。

您可能会认为 (3) 就像使用 PInvoke 代码编写 C# 代码来访问本机内容 - 只不过所有 PInvoke 内容都是为您生成的。

当然,它的作用还不止于此,还有一些注意事项 - 但这应该让您了解它的用途。

换句话说,它实际上是一种胶水语言。虽然您可以使用 C++/CLI 编写成熟的应用程序,但更常见的做法是将托管部分和本机部分分开,并使用 C++/CLI 比使用 PInvoke 更干净地桥接两者。

另一个常见用途是通过 .Net 库调用来扩展现有的本机 C++ 代码库。

请注意对代码进行良好分区,因为有时将纯 C++ 代码透明地编译为 IL 时可能会非常微妙!

至于你的旁注:PInvoke 是一种特殊类型的互操作。互操作也有其他形式,例如 COM 互操作。事实上,更准确地说,PInvoke 是一组使与本机代码的互操作变得更容易的语言功能。

With C++/CLI you can create, broadly speaking, three types of objects:

  1. Managed types. These will compile down to essentially the same IL as the equivalent C#. There is no performance opportunity here.
  2. Native types. Compiles down to native code as if you'd used straight C++.
  3. Mixed mode types. These compile down to managed code, but allow you to refer to native types too.

You might think of (3) as being like writing C# code with PInvoke code to accessing the native stuff - except all the PInvoke stuff is generated for you.

There's more to it than that, of course, as well as some caveats - but that should give you an idea of how it's useful.

In other words it's really a glue language. While you can write fully fledged apps in C++/CLI it's more normal to keep the managed and native parts separate and use C++/CLI to bridge the two more cleanly than with PInvoke.

Another common use is to extend and existing, native, C++ code base with .Net library calls.

Just be careful that you partition your code well as it can be quite subtle sometimes in compiling your pure C++ code down to IL transparently!

As to your sidenote: PInvoke is a particular type of Interop. Interop comes in other forms too, such as COM Interop. In fact, more accurately, PInvoke is a set of language features that make Interop with native code easier.

零時差 2024-08-20 14:34:01

我过去曾有效地使用过托管 C++(C++/CLI 的 .NET 1.1 前身)。我发现当您希望在托管代码中使用本机 C 或 C++ 库时,它效果最好。您可以采用整个 Interop/PInvoke 路线,这会产生一些丑陋的 C# 代码,并且经常出现编组问题,或者您可以编写托管 C++ 包装器,这是 C++/CLI 真正发挥作用的地方。

由于 C++/CLI 是托管代码,因此您可以通过添加对 .DLL 的引用,以正常方式从 C#(或 VB.NET,如果您倾向于这种方式)调用它。没有编组,没有 dllimport,没有任何愚蠢的事情。只是普通的项目参考。此外,如果您的本机库是这样设计的,您还可以获得静态链接库的好处,这是一件好事(tm)。

I've used Managed C++ (the .NET 1.1 precursor to C++/CLI) effectively in the past. I find it works best when you have a native C or C++ library you wish to use in managed code. You could go the whole Interop/PInvoke route, which makes for some ugly C# code and frequently has marshalling issues, or you could write a managed C++ wrapper, which is where C++/CLI really shines.

Because C++/CLI is managed code, you can call it from C# (or VB.NET if you lean that way) in the normal way, by adding a reference to the .DLL. No marshalling, no dllimport, nothing goofy like that. Just normal project references. Additionally, you get the benefit of static linked libraries if your native library is so designed, which is a Good Thing (tm).

栖竹 2024-08-20 14:34:01

某些应用程序是通过检查某个位置的所有 DLL 中具有特定名称的导出函数来扩展的。在 C# 中,无法声明本机 C 样式导出,但在 C++/CLI 中可以。我在 C++/CLI 中创建一个“包装器”,用于导出方法、处理 C 结构到托管对象的任何转换,并将调用传递给用 C# 编写的程序集。

Phil Nash really hit the big things. Here's one more that I've hit more than once and is the primary reason I've used C++/CLI in the past:

Some applications are extended by checked all DLLs in some location for exported functions with a particular name. In C#, there's no way to declare a native C-style export, but you can in C++/CLI. I create a "wrapper" in C++/CLI that exports the method, handles any translation of C structs to managed objects and passes the call on to an assembly written in C#.

紫南 2024-08-20 14:34:01

有些类型是其他语言所不可用的,例如模板,
const 和装箱值类型的跟踪句柄。

模板在编译时是专门化的。泛型在运行时是专门化的。尽管 CLR 应该缓存泛型专门化以供将来使用(因此每次使用时都会获得相同的列表),但每次请求泛型专门化时仍然会影响性能。

我知道其他语言放弃了 const 属性,但在 C++ 代码中进行编译时检查总比没有好。

使用像 int^ 这样的类型允许您访问托管堆目录上的内存,而无需进行不必要的拆箱。将装箱值的跟踪句柄传递给需要跟踪句柄的函数(例如 Console::WriteLine(Object^))时,这可以提高性能。当然早期的装箱初始化是无法避免的。在其他语言中,您可以将引用存储在对象变量中并将其传递以避免拆箱,但您会失去编译时类型检查。

There are certain types that are not available to other languages, such as templates,
const and tracking handle of boxed value types.

templates are specialized at compile-time. generics are specialized at runtime. Although CLR should cache generics specialization for future use (so you get the same List each time you use it), there is still a performance hit each time a generics specialization is requested.

i know other languages discard the const attribute, but have compile time checking in your C++ code is better than nothing.

Having a type like int^ allows you to access the memory on the managed heap directory without unnecessary unboxing. This can help performance when passing tracking handles of boxed values to functions that expect a tracking handle, such as Console::WriteLine(Object^). Of course the early boxing initialization can not be avoided. In other languages you can store the reference in an Object variable and pass it around to avoid unboxing, but you lose the compile time type check.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文