• ベストアンサー

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

  • C++の const int* dataを置き換える C#

    C#2005で、C++の const int* dataを置き換えるにはどうしたらよいでしょうか? メソッドの引数でdataを渡しているのですが、dataは intの配列です。 メソッド内では書きかえられたくないのでC++の時にconstを付けました。 C#ではどのように記述するのが正しいでしょうか? C++からC#に置き換えていますが、参考になるサイトがありましたら教えてください。

  • C言語のコールバック

    Java/C#/PHPといった言語はすでに使えるのですが、現在C言語およびWin32 APIを勉強中です。 C言語の関数にはJavaなどのインスタンスメソッドのthisにあたる引数が渡されませんが、Win32 APIのウィンドウプロシージャに代表されるコールバック関数において不都合があります。Javaの場合は、 interface Callback{ void onCallback(); } といったインターフェイスが定義されているものとして、 hoge(new Callback(){ int data = 10; public void onCallback(){ System.out.println(data); } }); のようなコードで引数以外のデータも参照できますが、C言語ではこのように引数で渡せないデータを参照するにはどうしたらよいでしょうか。グローバル変数として参照するのは、Javaのstaticなフィールドと同様に拡張性を損なうので避けたいと思います。

  • C#のキャストについて(object→byte)

    いつもお世話になっております。C#初心者です。 「メソッドの引数として渡された値をリスト型の配列に格納する」という課題に取り組んでいますが、 変数のキャストで実行時にエラーが発生し、頭を悩ませています。 作成したコードは以下のようになっています。 public class TestClass {  private List<byte> hogeList = new List<byte>();  public void TestMethod( object hoge )  {   hogeList.Add( (byte)hoge ); ← (*)  } } 上記のメソッドをMain関数から TestClass test = new TestClass(); test.TestMethod(5); として実行すると、「hogeList」に「5」が格納される、といった動作にしたいと考えています。 しかしながら、ビルドは通るのですが、実行すると(*)の位置で止まり、 「指定されたキャストは有効ではありません。」 というメッセージが表示されます。 そこで質問なのですが、object型からbyte型にキャストする場合にはどのような記述の仕方がありますでしょうか? ご教授よろしくお願いいたします。

  • 【Objective-C】文法 メソッドの定義について

    Objective-Cの勉強を始めたばかりの者です。 メソッドの定義について、混乱してきたので教えてください。 例えば、二つの数値を引数に与えるメソッドsetDataを作るとします。 このメソッドを以下のような方法で呼び出します。 id data; data = [[Data alloc] init]; [data setData:3:4]; この場合のメソッドの定義は以下の様になりますよね。 - (void)setData:(int)argx:(int)argy; 次にラベルを使った引数についてですが、 - (void)setData:(int)argx y(int)argy; と定義したら、呼び出しは、 [data setData:3 y:4]; となりますよね。 この記述に違和感を感じるんです。 ここまでは前ふりでして、以下が質問になるのですが、 メソッド名とは別に二つの引数用のラベルを設ける事ってできないのですか? つまりは、例えば、 [data setData x:3 y:4]; のような感じの記述です。 それとも、「ラベルを付けられるのは二つ目の引数から」ってのが仕様なんですか? 以上、ご指導のほど、宜しくお願いいたします。

  • ArrayクラスとtoStringについて

    問題集で次のプログラムを見掛ました。 public class Main{  public static void main(String args[]){   int[] array = new int[0];   System.out.println(array);  } } これを実行するとprintlnメソッドで toStringメソッドが呼び出されますが、 ArrayクラスはObjectクラスを継承しているため、 toStringメソッドもObjectクラスから継承されているので、 結果として、配列の要素数が0であっても、 エラー等が発生せずハッシュコードが表示される、ということです。 ObjectクラスのtoStringメソッドが ハッシュコードを返すものであるのは理解できます。 でも、なぜ要素数が1以上で何かしらの要素が存在する場合は、 ハッシュコードが返らないのでしょうか? 詳しい方、解説をお願いします。

  • c# 要素と値

     こんにちは、c#初心者です。  細かいことなんですが、気にしだしたら止まらなくなって、遂に質問です。  配列などで、そのインデックスの位置に含まれているオブジェクトは”値”と呼ばれているところを見かけるのですが、List<T>などのコレクションでは”要素”と呼ばれているのを見かけます。  例えば、Array.IndexOfメソッドでは、XMLに「値を検索します」と書かれている上に、「T value」と値であることが明記してあります。  一方、List<T>のIndexOfメソッドでは、”要素”と書かれていて、「T item」となっています。  「配列の中身は値(value)、コレクションの中身は要素(item)と区別しているのか」と納得しかけていた矢先、Array.Exists 「指定された配列に、……”要素”が……」と配列でも要素という単語が使用されているじゃないですか!  もう訳が分かりません。確かに、値と要素なら大して意味の違いはないので読み手には問題ないですが、書き手にとってはどう使い分ければよいのかちんぷんかんぷんです。  どなたか使い分けの分かる人がいらっしゃいましたら教えていただけませんか?

  • 配列とその要素数をメンバにもつ構造体

    C言語では,配列を引数とするときに,合わせて要素数を渡さなければいけないといわれます. そこで,配列とその要素数をメンバにもつ構造体を定義して,これを要素数つき配列のように扱えば,引数として渡す場合には,この構造体を渡すだけでよいと思うのですが,このような用法は一般的に用いられているでしょうか. 単純なアイデアだと思うんですが,あまり紹介されているのを見たことがありません. もしあまり用られない用法であれば,その理由を教えてください. 現在,プログラムを書いているのですが,引数の多さに閉口しており,上の考えで,引数を減らしたいと考えています.  よろしくお願いいたします.

  • java ソート

    java ソート ソートプログラムを作ってみましょう ? double型の配列とメソッドを持つクラスを定義 ? コンストラクタで配列を初期化(0.0で初期化) ?配列を昇順,降順に並び替えるメソッドを持つこと ? 2種類のメソッドを持っても良い ? 引数の値で変えても良い ? ソート済み配列をチェックするメソッドを持つこと ? 1000000要素程度のソーティングで時間計測 課題です 全く手が出せず困ってます・・・。 ヒント、手順、解答 なんでも良いので、救いの手をお願いします!!

  • 配列について質問

    僕はjava初心者です、ご回答は優しくお願いします! 質問1:配列の定義について、本質的には「配列要素の集合」のことでしょうか? 違ったら、その本質をご教示ください。 質問2:配列は、オブジェクトだとjavaの参考書には書かれていました。そして、オブジェクトとは、「データとそれを操作する機能(メソッド)がひとまとまりになったもの」とも書いてありました。 ここでいう「データ」とはなんですか?配列要素のことですか? 質問3:配列とは、ヒープ内にある「配列要素の集合を保管した箱」でしょうか?

    • ベストアンサー
    • Java
  • C言語とfortranでのデータの受け渡しについて

    はじめましてc_f_gaussと申します。 現在fortranで動的に配列を得るためにC言語を使用し 配列を確保しそのアドレスをfortranで定義してある 配列のアドレスと交換したいのですがどのようにしたら よいでしょうか? 今の段階ではC言語側でアドレスを交換してもfortran 側に戻ると元のアドレスに戻ってしまいます。 fortranとC言語でデータ受け渡すには何か必要な手続き があるのでしょうか?