継承、集約、およびコンテインメント
更新 : 2007 年 11 月
.NET Framework での COM の再利用は、継承によって実現されます。COM の型は基本クラスとして継承に参加できます。継承、集約、またはコンテインメントの各モデルは次の条件に従って使用してください。
モデル |
用途 |
---|---|
継承 |
マネージ オブジェクトを外部オブジェクトとして公開します。 |
集約 |
外部オブジェクトが、インターフェイスの別のオブジェクトの実装を変更せずに公開できるようにします。 |
コンテインメント |
外部オブジェクトが、内部オブジェクトの動作を変更できるようにします。 |
継承
マネージ インターフェイスを COM に公開すると、そのインターフェイスがマネージ側の別のインターフェイスから継承された場合でも、マネージ インターフェイスは、常に IUnknown または IDispatch を拡張します。これと同じ規則が、マネージ クラスに対して生成されるクラスのインターフェイスにも適用されます。
.NET Framework は、実装の継承を追加することにより、COM モデルを拡張して再利用できるようにします。マネージ型は、COM コクラスから、つまり、ランタイムによって生成されるランタイム呼び出し可能ラッパー (RCW: Runtime Callable Wrapper) から、直接または間接的に派生させることができます。派生した型は、COM オブジェクトのすべてのメソッドとプロパティ、およびマネージ コードに実装されているメソッドとプロパティを公開できます。その結果、オブジェクトの一部分はマネージ コードで実装され、別の部分はアンマネージ コードで実装されます。
基本クラスとして修飾するには、コクラスは次の条件を満たしている必要があります。
作成可能
(COM で) 集約可能
マネージ型は、修飾するコクラスの RCW を拡張し、基本オブジェクトによって提供されるメソッドをオーバーライドできます。インターフェイスのすべてのメソッドをオーバライドする場合は、すべての基本メソッドをオーバーライドする必要があります。
マネージ基本オブジェクトから継承する場合と同じ方法で、RCW からマネージ型を継承できます。COM の型である AcmeLib.Slingshot からマネージ クラス Catapult が派生するコード例を次に示します。
#using "AcmeLib.dll" // Provides definition of Slingshot.
__gc class Catapult : public AcmeLib.Slingshot // Extends the COM type.
{
// Delegates to base implementation.
Load() { //… };
Fire()
{
// Engages in some behavior before delegating to the base
// implementation.
Slingshot::Fire();
}
// The Aim method needs to be overridden.
Aim() { //… }
}
Catapult *cp = new Catapult();
// Calls derived implementation.
cp->Load();
// Calls base implementation.
cp->Aim();
// Calls derived which delegates to base.
cp->Fire();
集約
ある COM クラスのインターフェイスを別の COM クラスに実装されているかのように公開するには、最初の COM クラスを 2 番目の COM クラスに集約します。COM オブジェクトは、.NET オブジェクトを集約できます。この場合は、外部オブジェクトを通じて、そのオブジェクトのすべてのインターフェイス (クラス インターフェイスを含めて) を利用できます。内部の .NET オブジェクトは、その IUnknown への呼び出しを、外側の IUnknown に送ります。
集約は、次のセクションで説明するコンテインメントより少し複雑です。一般に、集約は、外部オブジェクトが、別のオブジェクトのインターフェイス実装を変更せずに公開できるようにするために使用します。すべてのマネージ オブジェクトは、内部オブジェクトとして使用されるマネージ オブジェクトとの COM スタイルの集約を自動的にサポートします。マネージ オブジェクトを集約するには、アンマネージ外部オブジェクトは、CoCreateInstance を呼び出してマネージ内部オブジェクトを作成し、その後でその外側の IUnknown を OuterUnknown パラメータとして渡します。構築中に外側の IUnknown がマネージ オブジェクトに渡されると、そのマネージ オブジェクトはそのインターフェイスをキャッシュし、次のように使用します。
外部オブジェクトは、内部 IUnknown の呼び出しを転送しない IUnknown を保持します。呼び出しを転送しない IUnknown は、通常の IUnknown と同じように動作します。つまり、オブジェクトがインターフェイスを実装していれば成功し、それ以外の場合は失敗します。呼び出しを転送しない IUnknown は、そのインターフェイスへの呼び出しを外部オブジェクトに転送しません。
内部オブジェクトに対してそのオブジェクトがサポートしていないインターフェイスを照会すると、内部オブジェクトはその呼び出しを外側の IUnknown インターフェイスに転送します。
内部オブジェクトの QueryInterface、AddRef、Release の各メソッドへの呼び出しはすべて、外側の IUnknown に転送されます。
上の 3 つの動作により、すべてのマネージ オブジェクトを集約できます。この種の集約関係により、1 つの COM オブジェクトの一部をマネージ コードで実装し (内側の部分)、さらに別の一部をアンマネージ コード (外側の部分) で実装することが可能です。
コンテインメント
.NET オブジェクトのメタデータを .NET アセンブリにインポートし、別のクラス内でその型のデータ メンバを宣言することにより、.NET オブジェクトに COM オブジェクトを含めることができます。通常の COM コンテインメントと同じように、独自のインターフェイス実装でその COM オブジェクトのインターフェイスを呼び出すことができますが、含まれているオブジェクトはクラスの外部には公開されません。コンテインメントは、集約より単純です。外部オブジェクトが内部オブジェクトの動作を変更する必要があるときは、通常、コンテインメントが使用されます。コンテインメントを行うために、外部オブジェクトは、そのコンストラクタに内部オブジェクトのインスタンスを作成し、必要に応じて呼び出しを内部オブジェクトにデリゲートします。外部オブジェクトは、デリゲートする呼び出しと、直接処理する呼び出しを選択できます。ランタイムには、コンテインメントをサポートするためのオブジェクトに対する特別の要件はありません。
COM オブジェクトに、.NET オブジェクトを含めることもできます。COM オブジェクトのクライアントに関する動作は、他のいずれかの COM オブジェクトを含んでいる場合とまったく同じです。
参照
概念
.NET Framework への COM コンポーネントの公開
COM への .NET Framework コンポーネントの公開