マネージド型 (C++/CLI)
Visual C++ を使うと、マネージド型を介して .NET の機能にアクセスできます。これにより、共通言語ランタイムの機能をサポートします。また、ランタイムの利点と制限が適用されます。
マネージド型とメイン関数
使用して /clr
アプリケーションを記述する場合、関数の引数を main()
マネージド型にすることはできません。
適切な署名の例を次に示します。
// managed_types_and_main.cpp
// compile with: /clr
int main(int, char*[], char*[]) {}
C++ ネイティブ型と同等の .NET Framework
次の表は、Visual C++ の組み込み型のキーワードを示しています。これは、System 名前空間の定義済み型の別名です。
Visual C++ 型 | .NET Framework 型 |
---|---|
void |
System.Void |
bool |
System.Boolean |
signed char |
System.SByte |
unsigned char |
System.Byte |
wchar_t |
System.Char |
short および signed short |
System.Int16 |
unsigned short |
System.UInt16 |
int 、signed int 、long 、および signed long |
System.Int32 |
unsigned int および unsigned long |
System.UInt32 |
__int64 および signed __int64 |
System.Int64 |
unsigned __int64 |
System.UInt64 |
float |
System.Single |
double および long double |
System.Double |
既定値を signed char
または unsigned char
にするコンパイラ オプションの詳細については、「/J
(既定の char
型の unsigned
への変更)」を参照してください。
ネイティブ型で入れ子になった値型のバージョンの問題
クライアント アセンブリのビルドに使われる署名済み (厳密な名前の) アセンブリ コンポーネントについて考えてみましょう。 このコンポーネントには、ネイティブの共有体、クラス、または配列のメンバーの型としてクライアントで使われる値型が含まれています。 コンポーネントの将来のバージョンで、値型のサイズまたはレイアウトが変更された場合、クライアントを再コンパイルする必要があります。
sn.exe (sn -k mykey.snk
) を使ってキーファイルを作成します。
例
次のサンプルはコンポーネントです。
// nested_value_types.cpp
// compile with: /clr /LD
using namespace System::Reflection;
[assembly:AssemblyVersion("1.0.0.*"),
assembly:AssemblyKeyFile("mykey.snk")];
public value struct S {
int i;
void Test() {
System::Console::WriteLine("S.i = {0}", i);
}
};
このサンプルはクライアントです。
// nested_value_types_2.cpp
// compile with: /clr
#using <nested_value_types.dll>
struct S2 {
S MyS1, MyS2;
};
int main() {
S2 MyS2a, MyS2b;
MyS2a.MyS1.i = 5;
MyS2a.MyS2.i = 6;
MyS2b.MyS1.i = 10;
MyS2b.MyS2.i = 11;
MyS2a.MyS1.Test();
MyS2a.MyS2.Test();
MyS2b.MyS1.Test();
MyS2b.MyS2.Test();
}
この例では、次の出力が生成されます:
S.i = 5
S.i = 6
S.i = 10
S.i = 11
説明
ただし、別のメンバーを in nested_value_types.cpp
にstruct S
追加し (たとえば)、double d;
クライアントも再コンパイルせずにコンポーネントを再コンパイルした場合、結果はハンドルされない例外 (型System.IO.FileLoadException) になります。
等価性をテストする方法
次のサンプルでは、Managed Extensions for C++ を使った等値のテストは、ハンドルが参照する対象に基づいています。
例
// mcppv2_equality_test.cpp
// compile with: /clr /LD
using namespace System;
bool Test1() {
String ^ str1 = "test";
String ^ str2 = "test";
return (str1 == str2);
}
このプログラムの IL は、戻り値が 〘 の呼び出し op_Equality
を使用して実装されていることを示しています。
IL_0012: call bool [mscorlib]System.String::op_Equality(string, string)
アセンブリの互換性の問題を診断して修正する方法
コンパイル時に参照されるアセンブリのバージョンが実行時に参照されるアセンブリのバージョンと一致しない場合は、さまざまな問題が発生する可能性があります。
アセンブリをコンパイルするときに、他のアセンブリを #using
構文で参照することがあります。 コンパイル時に、これらのアセンブリにはコンパイラからアクセスされます。 これらのアセンブリからの情報は、最適化の判断に使われます。
ただし、参照アセンブリが変更および再コンパイルされた場合は、それに依存する参照アセンブリも再コンパイルします。 そうしないと、アセンブリに互換性がなくなる可能性があります。 最初に有効だった最適化の決定は、新しいアセンブリ バージョンでは正しくない可能性があります。 これらの非互換性のために、さまざまなランタイム エラーが発生する可能性があります。 このような場合に発生する特定の例外はありません。 実行時にどのように障害が報告されるかは、問題の原因となったコード変更の性質によって異なります。
リリースされたバージョンの製品用にアプリケーション全体が再構築されている限り、これらのエラーは最終的な運用コードで問題になりません。 一般にリリースされるアセンブリには公式のバージョン番号を付けるようにします。そうすることで、このような問題を確実に回避できます。 詳細については、「アセンブリのバージョン管理」を参照してください。
非互換性エラーを診断して修正するには
別のアセンブリを参照するコードでランタイム例外またはその他のエラー条件が発生する可能性があります。 別の原因を特定できない場合、問題は古いアセンブリである可能性があります。
まず、例外やその他のエラー条件を分離して再現してください。 古い例外が原因で発生する問題は、おそらく再現可能です。
アプリケーションで参照されるすべてのアセンブリのタイムスタンプを確認します。
参照されているアセンブリのタイムスタンプが、アプリケーションの最終コンパイルのタイムスタンプよりも後の時刻である場合、アプリケーションは最新ではありません。 古い場合は、最新のアセンブリを使用してアプリケーションを再コンパイルし、必要に応じてコードを編集します。
アプリケーションを再実行し、問題を再現する手順を実行し、例外が発生しないことを確認します。
例
次のプログラムは問題を示しています。最初にメソッドのアクセシビリティを低下させ、次に再コンパイルせずに別のアセンブリでそのメソッドにアクセスしようとします。 最初にコンパイル changeaccess.cpp
します。 これは、変更される参照アセンブリです。 次に referencing.cpp
をコンパイルします。 正常にコンパイルされます。 次に、呼び出されたメソッドのアクセシビリティを減らします。 changeaccess.cpp
コンパイラ オプション/DCHANGE_ACCESS
を使用して再コンパイルします。 メソッドではなくメソッドpublic
をprotected
access_me
作成するため、外部Test
またはその派生物から呼び出すことはできません。 referencing.exe
を再コンパイルせずに、アプリケーションを再実行します。 A MethodAccessException が発生します。
// changeaccess.cpp
// compile with: /clr:safe /LD
// After the initial compilation, add /DCHANGE_ACCESS and rerun
// referencing.exe to introduce an error at runtime. To correct
// the problem, recompile referencing.exe
public ref class Test {
#if defined(CHANGE_ACCESS)
protected:
#else
public:
#endif
int access_me() {
return 0;
}
};
参照元アセンブリのソースを次に示します。
// referencing.cpp
// compile with: /clr:safe
#using <changeaccess.dll>
// Force the function to be inline, to override the compiler's own
// algorithm.
__forceinline
int CallMethod(Test^ t) {
// The call is allowed only if access_me is declared public
return t->access_me();
}
int main() {
Test^ t = gcnew Test();
try
{
CallMethod(t);
System::Console::WriteLine("No exception.");
}
catch (System::Exception ^ e)
{
System::Console::WriteLine("Exception!");
}
return 0;
}
関連項目
C++/CLI を使用した .NET プログラミング (Visual C++)
他の .NET 言語との相互運用性 (C++/CLI)
マネージド型 (C++/CLI)
#using
ディレクティブ