• ベストアンサー

C# Object型の受け渡し

C++のプログラマです。 以下のコードを通すとdataが配列として配置されます。 Object data; excute(out data); excuteメソッドの引数定義はVARIANT * です。 ここで質問です。 1)C++の概念ではこのような使い方は考えられないのですが、   C#ではあたりまえでしょうか? 2)この場合、配列数と配列の要素を取出す方法を教えてくれませんか? 以上、宜しくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

>1)C++の概念ではこのような使い方は考えられないのですが、 >  C#ではあたりまえでしょうか? 「このような」というのは、一体どの部分を指しているのでしょう。 (a) 「ref object で渡した物が VARIANT* で受け取れる」という部分に関してであれば、 これは C# と C++ の相互運用の為に、間に Marshaller (変換機構) が存在している為で、C# の中だけで使っている限りにおいては、C++ と同様に、勝手に引数の型が変換されるといった事はありません。 (b) 「参照を引数に渡して、そのオブジェクトを初期化してもらう」といった使い方に関してであれば、 この方法は C++ でも普通に使われる方法です。むしろ、C# ではその様な使い方の濫用を防ぐ為に、意識して ref や out などのキーワードをつけないと、その様な使い方ができない様になっています。 >2)この場合、配列数と配列の要素を取出す方法を教えてくれませんか? data を対応する配列型にキャストして下さい。 例えば VT_ARRAY | VT_UI4 ならば (uint[])data, VT_ARRAY | VT_BSTR ならば (string[])data など。 ---------- 例を載せます // C++ 側 (okwave.dll とする) extern "C" __declspec(dllexport) void excute(VARIANT* data){ static const int numberOfElements=10; SAFEARRAYBOUND abound={numberOfElements,0}; SAFEARRAY* parray=SafeArrayCreate(VT_UI4,1,&abound); DWORD* elem; if(SUCCEEDED(SafeArrayAccessData(parray,reinterpret_cast<void**>(&elem)))){ for(int i=0;i<numberOfElements;i++) elem[i]=i*(i+1)/2; SafeArrayUnaccessData(parray); } VariantInit(data); V_VT(data)=VT_ARRAY|VT_UI4; V_ARRAY(data)=parray; } //-------------------- // C# 側 using System.Runtime.InteropServices; static class Program{ [DllImport("okwave.dll")] static extern void excute([Out][MarshalAs(UnmanagedType.Struct)]out object data); static void Main(){ object data; excute(out data); if(data==null){ System.Console.WriteLine("data is null"); return; } System.Console.WriteLine("data = {0} : {1}",data,data.GetType()); uint[] data_=data as uint[]; // キャスト→ data_ は通常の配列と同じに使える、というか、通常の配列である。 if(data_==null){ System.Console.WriteLine("data is not an array."); return; } for(int i=0;i<data_.Length;i++){ uint elem=data_[i]; System.Console.WriteLine("data[{0}] = {1}",i,elem); } } }

mindeyed
質問者

補足

COM内部からの細かなご説明有難うございます。 キャストで対応できました。 有難うございます。 >「このような」というのは、一体どの部分を指しているのでしょう。 処理が終わった後に戻ってくる引数が1つの変数から 配列に代わる事を示していました。

その他の回答 (1)

  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.2

> excuteメソッドの引数定義はVARIANT * です。 これは何なのかよく分からないので別の人の解説を待ちたい。 そうねぇ・・・・。まぁoutキーワードがあるからね。これはC++で言えば、 void hogehoge::execute(variant* data); にポインタを渡すことのような感じ。つまり、関数内部でdataの中身をいじくることができて、 関数から戻ってきた時にdataの中身はいじられた内容になっているという事。 C#のoutはこれに似て非なる振る舞いをするが、一番の違いは「実引数がnullでもいい」という事。 先ほどのC++では以下のようなものは許されない。 ~~~~ここから~~~~ hogehoge hoge = new hogehoge(); VARIANT *a = null; hoge->execute(a); // ←execute内でそのまま使ったらぬるぽだしexecute内で何かをnewしても意味ない。 ~~~~ここまで~~~~ だけど、C#のout仮引数では可能。 ~~~~ここから~~~~ hogehoge hoge = new hogehoge(); object a = null; hoge.execute(a); // ←executeから戻ってきたらnullじゃない。 if(a.IsArray()) { object[] o = (object[])a; for(int i = 0; i < o.Length; i++) { // 何かする } } ~~~~ここまで~~~~ ただ・・・・パラメータ修飾子outを使う時に何が返ってくるか分からない(VBでいうVarant的な)というのは考えにくいというかCOM(ActiveX)との相互運用以外でそんなものがあったら設計自体がおかしいような気はするね。

mindeyed
質問者

補足

なるほど、分かりやすい説明有難うございます。 上記の内容で解決出来ました。 確かにCOMのインターフェイス仕様ははっきりしてほしいものです。。

関連するQ&A