2016-09-27 12 views
1

関数の最初のパラメータをコンテキストオブジェクト(一貫してタイプt_contextと呼ぶ)を一貫して使用するC(C++ではない)ライブラリがあり、SWIGを使用してC#ラッパーはこのスタイルの呼び出しを保持しています(つまり、関数が多少なりとも孤立しているのではなく、いくつかのクラスのメソッドとしてラップし、メソッド内のthisオブジェクトからの参照を介してt_contextにアクセスします)。SWIG:OOの方法でC APIをラップする

例(C署名):

void my_lib_function(t_context *ctx, int some_param); 

希望C#のAPI:

class Context 
{ 
    // SWIG generated struct reference 
    private SWIG_t_context_ptr ctx; 

    public void my_lib_function(int some_param) 
    { 
     // call SWIG generated my_lib_function with ctx 
    } 
} 

誰かが再び(既存のCのために私にSWIG生成されたラッパーを指摘するならば、私も幸せになりたいです:not C++)このAPIスタイルを使用するライブラリ。私は何も見つけることができませんでした。

また、SWIG以外のCからC#のユースケース用のラッパージェネレータがあります(コード生成に使用されるテンプレートを公開するなど)。

+0

複数のC関数からクラスを作成したい場合は、何らかの方法でインターフェイスジェネレータに特定のクラスに属する関数を伝える必要があります。最も簡単な方法は、匿名のstruct、typedef struct _Context Context;を使用し、 '%extend'ディレクティブを使用してラップされたC関数を呼び出すメンバ関数を追加することです。 '.i'ファイルに各関数の3行を追加する必要があります。これは、C++クラスでCをラップする方法と同様です。このようにして、元のヘッダを変更することなく、Cライブラリを再コンパイルする必要はありません。 –

+0

関数にはどのクラスに属しているのかを推測できる命名規則はありますか?それがオプションであれば、あなたが望むものをさらに自動化することができます。 – Flexo

+0

はい、私は関数の命名を制御しているので、このようにして公開されるべきすべての関数の名前をmy_lib_api_ *とするのは簡単でしょう。 – pmf

答えて

1

この問題を解決するために、以下のミニヘッダーファイルを作成して、実際にこれを行う気になるすべての部分を実証しました。

  1. C#のユーザーは、ここでは何も起こっていないことに気づくべきではありません。
  2. SWIGモジュールのメンテナーは、できるだけすべてをエコーし​​て、手作業でたくさんのプロキシ関数を書く必要はありません。いくつかのスタブ実装と

    #ifndef TEST_H 
    #define TEST_H 
    
    struct context; 
    typedef struct context context_t; 
    
    void init_context(context_t **new); 
    
    void fini_context(context_t *new); 
    
    void context_func1(context_t *ctx, int arg1); 
    
    void context_func2(context_t *ctx, const char *arg1, double arg2); 
    
    #endif 
    

    と、対応するtest.cの:

    #include <stdlib.h> 
    #include "test.h" 
    
    struct context {}; 
    typedef struct context context_t; 
    
    void init_context(context_t **new) { 
        *new = malloc(sizeof **new); 
    } 
    
    void fini_context(context_t *new) { 
        free(new); 
    } 
    
    void context_func1(context_t *ctx, int arg1) { 
        (void)ctx; 
        (void)arg1; 
    } 
    
    void context_func2(context_t *ctx, const char *arg1, double arg2) { 
        (void)ctx; 
        (void)arg1; 
        (void)arg2; 
    } 
    

    はいくつかあります物事をキックオフする

は、私は次のヘッダーファイル、TEST.Hを書きましたこれをきれいで使いやすいOO C#インターフェイスにするために解決する必要のあるさまざまな問題。一度に1つずつ作業し、最後に私の好みの解決策を提示します。 (この問題は、Pythonの方が簡単な方法で解決できますが、ここの解決策はPython、Java、C#などにも適用されます)

問題1:コンストラクタとデストラクタ。

通常、OOスタイルのC APIでは、(おそらく不透明な)設定をカプセル化する何らかの種類のコンストラクタとデストラクタ関数があります。私たちは、むしろC++のコンストラクタ/デストラクタどのように見えるかを書くこと%extendを使用することができます賢明な方法でターゲット言語にそれらを提示するには、まだC.

としてSWIG処理
%module test 

%{ 
#include "test.h" 
%} 

%rename(Context) context; // Make it more C# like 
%nodefaultctor context; // Suppress behaviour that doesn't work for opaque types 
%nodefaultdtor context; 
struct context {}; // context is opaque, so we need to add this to make SWIG play 

%extend context { 
    context() { 
    context_t *tmp; 
    init_context(&tmp); 
    // we return context_t * from our "constructor", which becomes $self 
    return tmp; 
    } 

    ~context() { 
    // $self is the current object 
    fini_context($self); 
    } 
} 

問題2の後に出てくるされています。メンバーを関数

私がこれを設定した方法では、かわいいトリックを使うことができます。我々は言うとき:

%extend context { 
    void func(); 
} 

SWIGが、その後のように見えるスタブを生成:離れてから取るように

SWIGEXPORT void SWIGSTDCALL CSharp_Context_func(void * jarg1) { 
    struct context *arg1 = (struct context *) 0 ; 

    arg1 = (struct context *)jarg1; 
    context_func(arg1); 
} 

二つのことをそのとおりです。

  1. context::func拡張機能を実装コールが呼び出されるcontext_func
  2. この関数には、暗黙の「これ」の引数があります。 ent 1常に

上記は、私たちが最初にC側を包むように設定したものとほとんど同じです。だから、それをラップするために、我々は単に行うことができます。これは、同様に私は期待したいと私の目標のかなりのミートポイント#2ない

%module test 

%{ 
#include "test.h" 
%} 

%rename(Context) context; 
%nodefaultctor context; 
%nodefaultdtor context; 
struct context {}; 

%extend context { 
    context() { 
    context_t *tmp; 
    init_context(&tmp); 
    return tmp; 
    } 

    ~context() { 
    fini_context($self); 
    } 

    void func1(int arg1); 

    void func2(const char *arg1, double arg2); 
} 

あなたが使用しない限り、あなたは(手動で関数宣言を記述する必要があります%includeでトリックし、個々のヘッダファイルを保持する)。 Pythonでは、インポート時にすべての要素をまとめて、もっと簡単に保つことができますが、SWIGが.csファイルを生成する時点でパターンに合ったすべての関数を適切な場所に列挙するきちんとした方法はありません。私は次のコードで(モノを使用して)テストするため

これは十分であった:

using System; 

public class Run 
{ 
    static public void Main() 
    { 
     Context ctx = new Context(); 
     ctx.func2("", 0.0); 
    } 
} 

解決することが可能と私は過去に取り上げてきた同様の質問looking at Javaあるother variants of C OO style design, using function pointersがあります。

関連する問題