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 /clr
schreiben, 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_Equality
implementiert 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.
Isolieren und reproduzieren Sie zuerst die Ausnahme oder eine andere Fehlerbedingung. Ein Problem, das aufgrund einer veralteten Ausnahme auftritt, sollte reproduzierbar sein.
Überprüfen Sie den Zeitstempel aller Assemblys, auf die in Ihrer Anwendung verwiesen wird.
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.
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.cpp
dann . 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.exe
erneut 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