Verwaltete Typen (C++/CLI)

Visual C++ ermöglicht den Zugriff auf .NET-Features über verwaltete Typen, die Unterstützung für Features der Common Language Runtime bieten und den Vorteilen und Einschränkungen der Laufzeit unterliegen.

Verwaltete Typen und die Standard-Funktion

Wenn Sie eine Anwendung mit /clrschreiben, können die Argumente der main() Funktion nicht von einem verwalteten Typ sein.

Ein Beispiel für eine ordnungsgemäße Signatur ist:

// managed_types_and_main.cpp
// compile with: /clr
int main(int, char*[], char*[]) {}

.NET Framework-Entsprechungen mit nativen C++-Typen

In der folgenden Tabelle sind die Schlüsselwort (keyword) für integrierte Visual C++-Typen aufgeführt, bei denen es sich um Aliase vordefinierter Typen im Systemnamespace handelt.

Visual C++-Typ .NET Framework-Typ
void System.Void
bool System.Boolean
signed char System.SByte
unsigned char System.Byte
wchar_t System.Char
short und signed short System.Int16
unsigned short System.UInt16
int, signed int, long und signed long System.Int32
unsigned int und unsigned long System.UInt32
__int64 und signed __int64 System.Int64
unsigned __int64 System.UInt64
float System.Single
double und long double System.Double

Weitere Informationen zur Compileroption für standard signed char oder unsigned char, siehe /J (Standardtyp char ist unsigned).

Versionsprobleme für Werttypen, die in nativen Typen geschachtelt sind

Erwägen Sie eine signierte Assemblykomponente (starker Name), die zum Erstellen einer Clientassembly verwendet wird. Die Komponente enthält einen Werttyp, der im Client als Typ für ein Mitglied einer systemeigenen Union, einer Klasse oder eines Arrays verwendet wird. Wenn eine zukünftige Version der Komponente die Größe oder das Layout des Werttyps ändert, muss der Client neu kompiliert werden.

Erstellen Sie eine Schlüsseldatei mit sn.exe (sn -k mykey.snk).

Beispiel

Das folgende Beispiel ist die Komponente.

// 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);
   }
};

Dieses Beispiel ist der Client:

// 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();
}

Das Beispiel generiert die folgende Ausgabe:

S.i = 5
S.i = 6
S.i = 10
S.i = 11

Kommentare

Wenn Sie jedoch ein weiteres Element struct S nested_value_types.cpp in (z. B double d;. ) hinzufügen und die Komponente neu kompilieren, ohne den Client erneut zu kompilieren, ist das Ergebnis eine unbehandelte Ausnahme (vom Typ System.IO.FileLoadException).

So testen Sie auf Gleichheit

Im folgenden Beispiel basiert ein Test auf Gleichheit, die verwaltete Erweiterungen für C++ verwendet, auf dem, worauf sich die Handles beziehen.

Beispiel

// mcppv2_equality_test.cpp
// compile with: /clr /LD
using namespace System;

bool Test1() {
   String ^ str1 = "test";
   String ^ str2 = "test";
   return (str1 == str2);
}

Die IL für dieses Programm zeigt, dass der Rückgabewert mithilfe eines Aufrufs op_Equalityimplementiert wird.

IL_0012:  call       bool [mscorlib]System.String::op_Equality(string, string)

Diagnostizieren und Beheben von Kompatibilitätsproblemen mit Assemblys

Wenn die Version einer Assembly, auf die zur Kompilierungszeit verwiesen wird, nicht mit der Version der Assembly übereinstimmt, auf die zur Laufzeit verwiesen wird, können verschiedene Probleme auftreten.

Wenn eine Assembly kompiliert wird, können auf andere Assemblys mit der #using Syntax verwiesen werden. Während der Kompilierung wird vom Compiler auf diese Assemblys zugegriffen. Informationen aus diesen Assemblys werden verwendet, um Optimierungsentscheidungen zu treffen.

Wenn die referenzierte Assembly jedoch geändert und neu kompiliert wird, kompilieren Sie auch die referenzierende Assembly, die davon abhängig ist. Andernfalls werden die Assemblys möglicherweise inkompatibel. Optimierungsentscheidungen, die zuerst gültig waren, sind möglicherweise für die neue Assemblyversion nicht richtig. Aufgrund dieser Inkompatibilitäten können verschiedene Laufzeitfehler auftreten. In solchen Fällen gibt es keine spezifische Ausnahme. Die Art und Weise, wie der Fehler zur Laufzeit gemeldet wird, hängt von der Art der Codeänderung ab, die das Problem verursacht hat.

Diese Fehler sollten in Ihrem endgültigen Produktionscode nicht auftreten, solange die gesamte Anwendung für die veröffentlichte Version Ihres Produkts neu erstellt wird. Assemblys, die für die Öffentlichkeit freigegeben werden, sollten mit einer offiziellen Versionsnummer gekennzeichnet werden, wodurch sichergestellt wird, dass diese Probleme vermieden werden. Weitere Informationen dazu finden Sie unter Assemblyversionen.

So diagnostizieren und beheben Sie einen Inkompatibilitätsfehler

Möglicherweise treten Laufzeit exceptions oder andere Fehlerbedingungen in Code auf, die auf eine andere Assembly verweisen. Wenn Sie keine andere Ursache identifizieren können, ist das Problem möglicherweise eine veraltete Assembly.

  1. Isolieren und reproduzieren Sie zuerst die Ausnahme oder eine andere Fehlerbedingung. Ein Problem, das aufgrund einer veralteten Ausnahme auftritt, sollte reproduzierbar sein.

  2. Überprüfen Sie den Zeitstempel aller Assemblys, auf die in Ihrer Anwendung verwiesen wird.

  3. Wenn die Zeitstempel von referenzierten Assemblys später als der Zeitstempel der letzten Kompilierung Ihrer Anwendung sind, ist die Anwendung veraltet. Wenn sie nicht mehr aktuell ist, kompilieren Sie Ihre Anwendung mit den neuesten Assemblys, und bearbeiten Sie den Code bei Bedarf.

  4. Führen Sie die Anwendung erneut aus, führen Sie die Schritte aus, die das Problem reproduzieren, und stellen Sie sicher, dass die Ausnahme nicht auftritt.

Beispiel

Das folgende Programm veranschaulicht das Problem: Zunächst wird die Barrierefreiheit einer Methode reduziert und dann versucht, auf diese Methode in einer anderen Assembly zuzugreifen, ohne erneut zu kompilieren. Zuerst kompilieren changeaccess.cpp . Es ist die referenzierte Assembly, die geändert wird. Kompilieren Sie referencing.cppdann . Es sollte erfolgreich kompiliert werden. Verringern Sie als Nächstes die Barrierefreiheit der aufgerufenen Methode. Kompilieren Sie das Kompilieren changeaccess.cpp mit der Compileroption /DCHANGE_ACCESS. Sie macht die access_me Methode protected, anstatt public, so dass sie nicht von außen Test oder ihren Ableitungen aufgerufen werden kann. Führen Sie die Anwendung ohne erneutes Kompilieren referencing.exeerneut aus. A MethodAccessException tritt auf.

// 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;
  }

};

Dies ist die Quelle für die referenzierende Assembly:

// 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;
}

Siehe auch

.NET-Programmierung mit C++/CLI (Visual C++)
Interoperabilität mit anderen .NET-Sprachen (C++/CLI)
Verwaltete Typen (C++/CLI)
#using-Direktive