マネージド型 (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
intsigned intlong、および 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.cppstruct 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 構文で参照することがあります。 コンパイル時に、これらのアセンブリにはコンパイラからアクセスされます。 これらのアセンブリからの情報は、最適化の判断に使われます。

ただし、参照アセンブリが変更および再コンパイルされた場合は、それに依存する参照アセンブリも再コンパイルします。 そうしないと、アセンブリに互換性がなくなる可能性があります。 最初に有効だった最適化の決定は、新しいアセンブリ バージョンでは正しくない可能性があります。 これらの非互換性のために、さまざまなランタイム エラーが発生する可能性があります。 このような場合に発生する特定の例外はありません。 実行時にどのように障害が報告されるかは、問題の原因となったコード変更の性質によって異なります。

リリースされたバージョンの製品用にアプリケーション全体が再構築されている限り、これらのエラーは最終的な運用コードで問題になりません。 一般にリリースされるアセンブリには公式のバージョン番号を付けるようにします。そうすることで、このような問題を確実に回避できます。 詳細については、「アセンブリのバージョン管理」を参照してください。

非互換性エラーを診断して修正するには

別のアセンブリを参照するコードでランタイム例外またはその他のエラー条件が発生する可能性があります。 別の原因を特定できない場合、問題は古いアセンブリである可能性があります。

  1. まず、例外やその他のエラー条件を分離して再現してください。 古い例外が原因で発生する問題は、おそらく再現可能です。

  2. アプリケーションで参照されるすべてのアセンブリのタイムスタンプを確認します。

  3. 参照されているアセンブリのタイムスタンプが、アプリケーションの最終コンパイルのタイムスタンプよりも後の時刻である場合、アプリケーションは最新ではありません。 古い場合は、最新のアセンブリを使用してアプリケーションを再コンパイルし、必要に応じてコードを編集します。

  4. アプリケーションを再実行し、問題を再現する手順を実行し、例外が発生しないことを確認します。

次のプログラムは問題を示しています。最初にメソッドのアクセシビリティを低下させ、次に再コンパイルせずに別のアセンブリでそのメソッドにアクセスしようとします。 最初にコンパイル changeaccess.cpp します。 これは、変更される参照アセンブリです。 次に referencing.cpp をコンパイルします。 正常にコンパイルされます。 次に、呼び出されたメソッドのアクセシビリティを減らします。 changeaccess.cppコンパイラ オプション/DCHANGE_ACCESSを使用して再コンパイルします。 メソッドではなくメソッドpublicprotectedaccess_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 ディレクティブ