2

我被要求将一些 C# 代码翻译成 C++/CLI。我的一位经理询问了两者之间翻译概念的潜在缺陷。

我很清楚这两种语言都被编译为通用接口语言,并通过相同的通用语言运行时运行。但是,可以保证一段为 .NET Framework 4.5 编译并调用 File.Exists(someFile); 的 C# 代码。将以与为 .NET Framework 4.5 编译并调用 File::Exists(someFile); 的一段 C++/CLI 代码完全相同的方式编译为 CIL;?

理论上答案是肯定的,因为这似乎是构建 .NET 框架的目的。但是,有没有办法验证这一点?是否有技术原因必须/不能是这种情况?

4

2 回答 2

3

当您编写 C++/CLI 代码并且您熟悉 C# 但不了解 C++/CLI 时,肯定会有一些陷阱。我会避免把它变成一个列表问题并列举所有这些问题,只是更常见的错误:

  • C++/CLI 要求您具体了解值类型和引用类型之间的差异的语言语法。您必须在引用类型引用上使用 hat^。喜欢String^ foo;。但有时你不这样做,你故意忽略它。喜欢StreamReader file;。这启用了“堆栈语义”,这是对 C++ RAII 模式的模拟。或者换句话说,编译器会在文件变量超出范围时自动处理它。您可以从 C# using语句中了解这一点。最大的陷阱是在你不应该戴帽子的时候戴帽子,比如int^ x = 42;。编译器会毫无怨言地接受它,但你最终会得到一个在运行时效率极低的盒装 int。

  • C++/CLI 语言和工具集的开发于 2005 年停止,此后一直处于维护模式。因此,它没有获得 C# 在那个时间范围内获得的好处,Linq 无疑是最重要的补充。没有 lambda 表达式支持,没有匿名类型,没有扩展方法。您不会喜欢转换使用这些语法结构的 C# 代码。

  • 考虑将 C# 转换为 C++/CLI 的原因只有一个,那就是利用它对与非托管代码互操作的强大支持。无需争论 pinvoke。一个非常常见的错误是将所有内容编译为 MSIL,包括本机 C++ 代码。效果太好了,C++/CLI 编译器能够将任何 C++ 编译为 IL,只要它是标准 C++03 兼容代码。但是结果是低效的,它肯定不会在运行时作为托管代码运行,并且像平常一样被 jitted,但没有来自本机代码生成器的好东西。哪个可以更好地优化代码。

  • 编译器的输出是纯 MSIL,与 C# 生成的完全相同。加上使用 C++ 的程序部分的本机代码,生成混合模式程序集。这使程序集依赖于进程的位数。或者换句话说,您可能从 C# 项目中知道的 AnyCPU 目标不适用。这是您在 EXE 项目中需要注意的事情,您必须明确平台目标设置。使用“x86”是确保您的程序在 64 位操作系统上运行时仍能正常工作的常见选择。如果您想在 64 位操作系统上将程序作为 64 位进程运行,那么您需要创建两个C++/CLI 程序集版本,并使用安装程序部署正确的一个。

您无需担心 File::Exists(somefile) 调用,在 MSIL 中调用该方法只有一种方法。C++/CLI 编译器将生成与 C# 编译器完全相同的 IL。如果您真的担心它,那么通过使用 ildasm.exe 之类的反编译器查看 IL 来建立信心

于 2013-07-22T10:57:10.123 回答
1

[C] 保证一段为 .NET Framework 4.5 编译并调用的 C# 代码将以与为 .NET Framework 编译的一段 C++/CLI 代码完全相同的方式File.Exists(someFile);编译到 CIL 4.5 和电话?File::Exists(someFile);

不,这不能保证。

事实上,甚至不能保证通过 C# 编译器两次运行相同的源代码会产生相同的二进制输出。因此,当然可以预期两种不同语言的两种不同编译器可能会生成不同的代码。

(请注意,它可能会,实际上它可能经常这样做。但我们在这里谈论的是保证。)

我无法理解的是为什么这可能很重要。当然,代码会同样的事情,因为它调用的是相同的方法。这不仅由文档保证,而且可以通过反汇编 .NET Framework DLL 进行自我验证。

只是不能保证这两个程序具有相同的二进制文件。一旦通过 JIT 编译器,无论如何都不会发生任何事情。这就是重点。

于 2013-07-22T08:58:54.007 回答