15 二月 2024
乍一看,翻译器似乎只有一种使用它的方法:通过向其提供 C# 代码,我们期望获得等效的 C++ 代码作为输出。 确实,这种方式是最常见的,但远非唯一的一种。 以下是代码翻译框架和相关实用程序提供的其他模式。
产品是由需要学习将代码转换为其他语言的过程和相关限制的程序员开发的。因此,出现了这样的情况,即从C#的角度来看,产品开发者所做的正确的更改会破坏其他语言的发布过程。
在项目开发过程中,我们尝试了几种方法来自动检测这样的问题:
限制C#语言的版本需要C#程序员的纪律,并且经常不方便。为了绕过这些限制,可以分两步进行转换:首先,将C#语言的最新版本的构造替换为过去标准中支持的类似的东西,然后直接进行转换。
使用过时的解析器为基础的转换器时,只能使用外部工具(例如,基于Roslyn的工具)来降低。另一方面,基于Roslyn的转换器会按顺序执行两个阶段,这样就可以在自己转换代码时和为旧工具转换代码时使用相同的代码。
这类似于转换产品代码,但意味着有些不同的要求。在转换数千万行的库时,首先最重要的是,尽可能严格地遵循原始C#代码的行为,即使以牺牲可读性为代价,也要这样做。因为,更简单但效果不同的代码会花费更长的时间来调试。另一方面,转换后的代码的使用示例应该尽可能简单,即使它与用C#写的原始示例的行为不一致,也要让C+程序员清楚地了解如何在C+中使用代码。
例如,在创建临时对象时,C#程序员经常使用using语句,以避免资源泄漏,并严格设置释放的时机,而不依赖于GC。using的严格转换会产生相当复杂的C+代码,因为有许多细微之处,比如"如果在"using
语句块中抛出异常,并且Dispose()
也抛出异常,哪一个会在捕获上下文中传递?"。这样的代码只会使C+程序员困惑,给人一种使用库很困难的印象,但实际上,只要在栈上有一个智能指针,它就会在适当的时候删除对象并释放资源。
提供API的库可以根据C#的惯例通过XML注释进行文档化。将注释转移到C+中,例如,转换为Doxygen格式,不是一件简单的事情。除了标记之外,还需要替换类型(C#中用点写全名,C+中用冒号对写)或其成员的引用,以及在使用属性的情况下,还需要理解它是getter还是setter。此外,还需要转换没有语义或可能不完整的代码片段。
这个任务是通过转换器本身的手段和外部工具来解决的。例如,通过分析生成的XML文档并额外准备片段,如方法的使用示例。
如我们所见,专业的代码转换框架,除了高质量地将C#代码转换为C++之外,还应该能够确定源代码的可转换性,必要时降低语言版本,转换转换后的库的使用示例和文档。