15 2月 2024
一見すると、トランスレータの使い方は1つしかないように思えるかもしれない。トランスレータにC#コードを与えることで、同等のC++コードが出力されると期待するのだ。実際、この方法が最も一般的ですが、それだけではありません。以下は、コード変換フレームワークと関連ユーティリティが提供する他のモードです。
製品は、コードを他の言語に変換する手順やそれに伴う制限事項を学ぶ必要があるプログラマーによって開発されています。その結果、C#の観点から正しいとされる製品開発者による変更が、他の言語のリリースプロセスを妨げるという状況が発生します。
プロジェクトの開発中、私たちはこのような問題を自動的に検出するいくつかの方法を試みました。
C#言語のバージョンを制限するには、C#プログラマーの規律が必要であり、しばしば不便です。これらの制限を回避するためには、変換を2段階で行うことができます。まず、C#言語の最新バージョンの構文を、過去の標準でサポートされている類似のものに置き換え、次に直接変換に進みます。
古いパーサーに基づく変換器を使用する場合、下げることは外部ツール(例えば、Roslynを基にしたユーティリティ)を使用することでしかできません。一方、Roslynに基づく変換器は、2つの段階を順番に実行することで、自分たちでコードを変換するときと、古いツールで変換するためにコードを準備するときの両方で同じコードを使用できるようにします。
これは製品コードの変換に似ていますが、やや異なる要件を意味します。数千万行のライブラリを変換するときには、まず何よりも、オリジナルのC#コードの振る舞いにできるだけ厳密に従うことが重要です。それは、読みやすさを犠牲にしてでもです。なぜなら、よりシンプルだが異なる効果のコードは、デバッグに時間がかかるからです。一方、変換されたコードの使用例は、できるだけシンプルに見えるようにする必要があります。C#で書かれたオリジナルの例と振る舞いが異なっていても、C++ でコードを使用する方法が明確になるようにする必要があります。
例えば、一時的なオブジェクトを作成するとき、C#プログラマーは、リソースの漏れを避け、GCに頼らずに解放のタイミングを厳密に設定するために、usingステートメントをよく使います。usingの厳密な変換は、"using
文のブロックで例外がスローされ、Dispose()
も例外をスローする場合、どちらの例外がキャッチコンテキストに渡されるか"という種類の多くのニュアンスのために、かなり複雑なC++ コードになります。このようなコードは、C++プログラマーを惑わせるだけで、ライブラリの使用が難しいという印象を与えますが、実際には、スタック上にスマートポインタを持っておけば十分で、適切なタイミングでオブジェクトを削除し、リソースを解放します。
APIを提供するライブラリは、C#の慣行に従ってXMLコメントで文書化することができます。コメントをC++ に移すことは、例えばDoxygen形式にすることは、簡単なことではありません。マークアップに加えて、型(C#ではフルネームがドットで書かれ、C++ ではコロンのペアで書かれる)やそのメンバーへの参照を置き換える必要があります。また、プロパティを使用する場合は、ゲッターかセッターかを理解する必要があります。さらに、意味を持たないか不完全な可能性のあるコード断片を変換する必要があります。 このタスクは、翻訳者自身と外部ユーティリティの両方によって解決されます、 例えば、生成されたXMLドキュメントを分析し、さらにメソッドの使用例などのフラグメントを準備することで解決します。
このように、コード変換のための専門的なフレームワークは、C#からC++への高品質の翻訳に加えて、ソースコードの翻訳可能性を判断し、必要に応じて言語バージョンを下げ、変換されたライブラリの使用例とそのドキュメントを翻訳することができるはずです。