SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

C++/CLIのSTL/CLR オブジェクトにC#からアクセスする方法

STL/CLRと.NET Frameworkの連携

vector オブジェクトを IEnumerable 型として返す C++/CLI ライブラリ

 vector 型はテンプレートが用いられているクラスなので、コンパイル時に型パラメータに指定された型に展開されます。C# や Visual Basic から、展開された型を認識することは可能ですが、vector 型そのものは非公開のアセンブリなので直接利用することはできません。そこで、インターフェイスを通して STL/CLR で生成した列挙子にアクセスします。まずは、vector オブジェクトを IEnumerable 型として返す C++/CLI のライブラリを作ってみましょう。

Sample01 C++/CLI
#include <cliext/vector>
#using <mscorlib.dll>

using namespace System;
using namespace System::Collections::Generic;
using namespace cliext;

public ref class Donor {
public:
    static IEnumerable<int>^ GetVector(int min, int max);
};

IEnumerable<int>^ Donor::GetVector(int min, int max) {
    vector<int>^ result = gcnew vector<int>();
    for (int i = min ; i < max ; i++)
        result->push_back(i);
    return result;
}

 Sample01 は、C++/CLI で書かれたプログラムです。このコードはエントリーポイントを持たないため、DLL ファイルとしてコンパイルしてください。STL/CLR のコンテナである vector<int> 型オブジェクトを IEnumerable<int> 型として返す Donor クラスの静的な GetVector() メソッドを用意しています。このメソッドは、単純に min パラメータで指定された値から max パラメータに指定された値までの要素を vector<int> 型のコンテナに追加し、結果を返します。メソッドの戻り値は IEnumerable<int> 型なので、このメソッドは、他のアセンブリからも参照することができます。

IEnumerable<int> を取得して列挙する C# プログラム

 次に、Sample01 で作成した Donor クラスの GetVector() メソッドから列挙子を取得してコンソールに各要素を出力するプログラムを C# 言語で書いてみましょう。

Sample02 C#
using System.Collections.Generic;

class Test
{
    public static void Main(string[] args)
    {
        IEnumerable<int> e = Donor.GetVector(0, 10);
        System.Console.WriteLine(e.GetType());
        foreach (int item in e)
            System.Console.WriteLine(item);
    }
}
実行結果
cliext.vector<int>
0
1
2
3
4
5
6
7
8
9

 Sample02 は C# 言語で書かれたプログラムです。このコードを見れば、Donor.GetVector() メソッドから取得した値を IEnumerable<int> として扱っているため、一般的な .NET Framework のコレクションと同じ方法でデータを処理できることが分かります。コンテナの生成や、要素を管理する処理は C++/CLI と STL/CLR を用い、結果だけを C# 言語で書かれた .NET Framework アプリケーション側で取得して利用することができます。このような方法であれば、高い技術力と経験のある C++ プログラマが、これまで十分テストされた STL を使った再利用可能なコードを応用してフレームワークを開発し、外部に公開する型は .NET Framework のコレクションとすることができます。他の一般的な .NET アプリケーション開発者は、実体が STL/CLR オブジェクトであることを意識する必要はありません。

Microsoft.VisualC.StlClr.IVector インターフェイス

 しかし、IEnumerable 型にキャストされてしまったコンテナは、当然 STL コンテナとしての機能は失われてしまいます。そうではなく、C# 言語で作られた .NET Framework アプリケーションから C++/CLI のコンテナを操作したい場合は、vector 型が実装している Microsoft.VisualC.StlClr.IVector インターフェイスを使います。

Microsoft.VisualC.StlClr.IVector インターフェイス (C#)
public interface IVector<TValue> : IRandomAccessContainer<TValue>,
    ICloneable, ICollection, IEnumerable 

 このインターフェイスは、vector 型が提供するメソッドを宣言しています。vector<T> は、他の言語から IVector<T> 型のインターフェイスとして操作できるため、STL/CLR の vector 型の機能を失うことなく、外部からオブジェクトにアクセスできます。同様の方法で、他の STL/CLR コンテナも Microsoft.VisualC.StlClr 名前空間内に用意されているインターフェイスを実装しています。C++/CLI 以外の言語から STL/CLR オブジェクトにアクセスするには、これらのインターフェイスを使います。また、IVector インターフェイスは IEnumerable を継承しているため、IVector 型のオブジェクトをコレクションとして扱うことにも問題ありません。

IVector<int> を返すように変更した C++/CLI ライブラリ

 では、Sample01 をベースに、生成した vector<int> オブジェクトを IVector<int> 型で返すライブラリを作ります。

Sample03 C++/CLI
#include <cliext/vector>
#using <mscorlib.dll>

using namespace System;
using namespace cliext;
using namespace Microsoft::VisualC::StlClr;

public ref class Donor {
public:
    static IVector<int>^ GetVector(int min, int max);
};

IVector<int>^ Donor::GetVector(int min, int max) {
    vector<int>^ result = gcnew vector<int>();
    for (int i = min ; i < max ; i++)
        result->push_back(i);
    return result;
}

 Sample03 は、Sample01 を書き換えて IEnumerable<int> の代わりに IVector<int> を返すようにしたプログラムです。IVector インターフェイスは、STL の vector 型が提供するメソッドを宣言しているため push_back() メソッドや size() メソッドに外部からアクセスできます。C# 言語で書かれたコードから、C++/CLI で作成されたコンテナに要素を追加したい場合などに利用できます。

IVector<int> を取得して列挙する C# プログラム

 次に、上で作成した Sample03 から IVector<int> 型のオブジェクトを取得し、コンテナを操作するコードを C# 言語で作ります。

Sample04 C#
using Microsoft.VisualC.StlClr;

class Test
{
    public static void Main(string[] args)
    {
        IVector<int> vector = Donor.GetVector(0, 10);
        System.Console.WriteLine(vector.GetType());
        for (int i = 0; i < vector.size(); i++)
            System.Console.WriteLine("vector[{0}]={1}", i, vector[i]);
    }
}
実行結果
cliext.vector<int>
vector[0]=0
vector[1]=1
vector[2]=2
vector[3]=3
vector[4]=4
vector[5]=5
vector[6]=6
vector[7]=7
vector[8]=8
vector[9]=9

 Sample04 は、Sample03 で作成した Donor クラスの GetVector() メソッドから IVector<int> 型のオブジェクトを取得し、内容を標準出力に出力するというものです。vector 型の size() メソッドやインデクサなどを使い、STL の vector 型と同じように操作できることが確認できます。ただし、IVector インターフェイスでは at() メソッドとインデクサの戻り値が異なっています。at() メソッドでは追跡参照を返しますが、インデクサはコンテナの型パラメータの指定された型をそのまま返します。

IVector インターフェイス at() メソッド
TValue% at(int _Pos)
IVector インターフェイスのインデクサ (C++/CLI)
property TValue Item[int _Pos] {
    TValue get (int _Pos);
    void set (int _Pos, TValue value);
}

 この違いは、おそらく C++/CLI 以外の言語からの利用を想定したものだと考えられます。本来 STL では、これらのメソッドとインデクサの振る舞いは同じものでしたが、STL に合わせて C++/CLI に依存する追跡参照を返すようにしてしまうと、他の言語から要素にアクセスできなくなってしまいます。

次のページ
イテレータ

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

赤坂 玲音(アカサカ レオン)

平成13年度「全国高校生・専門学校生プログラミングコンテスト 高校生プログラミングの部」にて最優秀賞を受賞。2005 年度~ Microsoft Most Variable Professional Visual Developer - Visual C++。プログラミング入門サイト WisdomSoft の管理人。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2474 2008/05/20 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー