SWIG を使用して C# インターフェイスを生成しようとしている非常に大規模で成熟した C++ コード ベースがあります。実際の C++ コード自体を変更することはできませんが、SWIG が提供するコードを拡張/更新するために使用することはできます。以下のように記述された C++ 関数が C# で問題を引き起こしているという問題に直面しています。
A* SomeClass::next(A*)
呼び出し元は次のようなことをするかもしれません:
A* acurr = 0;
while( (acurr = sc->next(acurr)) != 0 ){
if( acurr isoftype B ){
B* b = (B*)a;
...do some stuff with b..
}
elseif( acurr isoftype C )
...
}
基本的に、真の型に応じて異なる処理を行う要素のコンテナーを反復処理します。SWIG が生成した "next" 関数用の C# レイヤーは、残念ながら次のことを行います。
return new A();
そのため、C# の呼び出しコードは、返されたオブジェクトが実際に派生クラスであるかどうかを判断できず、実際には常に基本クラスのように見えます (これは理にかなっています)。私はいくつかの解決策に出くわしました:
- %extend SWIG キーワードを使用してオブジェクトにメソッドを追加し、最終的に dynamic_cast を呼び出します。私が見ているように、このアプローチの欠点は、継承階層を知る必要があることです。私の場合、それはかなり大きく、これはメンテナンスの問題だと思います。
- %factory キーワードを使用してメソッドと派生型を提供し、SWIG に dynamic_cast コードを自動的に生成させます。これは最初のソリューションよりも優れているように見えますが、詳しく見てみると、すべてのメソッドと、それが返す可能性のあるすべての派生型を探し出す必要があります。繰り返しますが、大きなメンテナンスの問題です。このドキュメントのリンクがあればいいのですが、見つかりません。SWIG に付属のサンプル コードを調べて、この機能を知りました。
- 派生オブジェクトのインスタンスを作成し、cPtr を新しいインスタンスに転送する C# メソッドを作成します。これは不器用だと思いますが、うまくいきます。以下の例を参照してください。
public static object castTo(object fromObj, Type toType) { オブジェクト retval = null; BaseClass fromObj2 = fromObj as BaseClass; HandleRef hr = BaseClass.getCPtr(fromObj2); IntPtr cPtr = hr.Handle; object toObj = Activator.CreateInstance(toType, cPtr, false); // 実際に私たちが考えているものであることを確認してください if (fromObj.GetType().IsInstanceOfType(toObj)) { オブジェクトに戻ります。 } retval を返します。 }
これらは本当にオプションですか?そして、既存のすべての関数とクラスの派生を掘り下げる気がない場合は、#3 が残っていますか? どんな助けでも大歓迎です。