Tipi gestiti (C++/CLI)
Visual C++ consente l'accesso alle funzionalità .NET tramite tipi gestiti, che forniscono supporto per le funzionalità di Common Language Runtime e sono soggetti ai vantaggi e alle restrizioni del runtime.
Tipi gestiti e funzione principale
Quando si scrive un'applicazione usando /clr
, gli argomenti della main()
funzione non possono essere di un tipo gestito.
Un esempio di firma corretta è:
// managed_types_and_main.cpp
// compile with: /clr
int main(int, char*[], char*[]) {}
Equivalenti di .NET Framework ai tipi nativi C++
La tabella seguente illustra le parole chiave per i tipi Visual C++ predefiniti, ovvero alias di tipi predefiniti nello spazio dei nomi System .
Tipo Visual C++ | Tipo .NET Framework |
---|---|
void |
System.Void |
bool |
System.Boolean |
signed char |
System.SByte |
unsigned char |
System.Byte |
wchar_t |
System.Char |
short e signed short |
System.Int16 |
unsigned short |
System.UInt16 |
int , signed int , long e signed long |
System.Int32 |
unsigned int e unsigned long |
System.UInt32 |
__int64 e signed __int64 |
System.Int64 |
unsigned __int64 |
System.UInt64 |
float |
System.Single |
double e long double |
System.Double |
Per altre informazioni sull'opzione del compilatore per impostazione predefinita su o , vedere/J
(Il tipo predefinito signed char
char
è unsigned
).unsigned char
Problemi di versione per i tipi valore annidati nei tipi nativi
Si consideri un componente assembly firmato (con nome sicuro) usato per compilare un assembly client. Il componente contiene un tipo di valore utilizzato nel client come tipo per un membro di un'unione nativa, una classe o una matrice. Se una versione futura del componente modifica le dimensioni o il layout del tipo di valore, il client deve essere ricompilato.
Creare un file di chiave con sn.exe (sn -k mykey.snk
).
Esempio
L'esempio seguente è il componente .
// 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);
}
};
Questo esempio è il 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();
}
L'esempio produce il seguente output:
S.i = 5
S.i = 6
S.i = 10
S.i = 11
Commenti
Tuttavia, se si aggiunge un altro membro a struct S
in nested_value_types.cpp
(ad esempio, double d;
) e si ricompila il componente senza ricompilare il client, il risultato è un'eccezione non gestita (di tipo System.IO.FileLoadException).
Come verificare l'uguaglianza
Nell'esempio seguente, un test di uguaglianza che usa Estensioni gestite per C++ si basa sugli handle a cui fanno riferimento gli handle.
Esempio
// mcppv2_equality_test.cpp
// compile with: /clr /LD
using namespace System;
bool Test1() {
String ^ str1 = "test";
String ^ str2 = "test";
return (str1 == str2);
}
Il programma mostra che il valore restituito viene implementato usando una chiamata a op_Equality
.
IL_0012: call bool [mscorlib]System.String::op_Equality(string, string)
Come diagnosticare e risolvere i problemi di compatibilità degli assembly
Quando la versione di un assembly a cui viene fatto riferimento in fase di compilazione non corrisponde alla versione dell'assembly a cui viene fatto riferimento in fase di esecuzione, possono verificarsi diversi problemi.
Quando un assembly viene compilato, è possibile fare riferimento ad altri assembly con la #using
sintassi . Durante la compilazione, questi assembly sono accessibili dal compilatore. Le informazioni di questi assembly vengono usate per prendere decisioni di ottimizzazione.
Tuttavia, se l'assembly a cui si fa riferimento viene modificato e ricompilato, ricompilare anche l'assembly di riferimento che dipende da esso. In caso contrario, gli assembly potrebbero diventare incompatibili. Le decisioni di ottimizzazione valide inizialmente potrebbero non essere corrette per la nuova versione dell'assembly. Possono verificarsi diversi errori di runtime a causa di queste incompatibilità. In questi casi non esiste alcuna eccezione specifica. Il modo in cui l'errore viene segnalato in fase di esecuzione dipende dalla natura della modifica del codice che ha causato il problema.
Questi errori non devono essere un problema nel codice di produzione finale, purché l'intera applicazione venga ricompilata per la versione rilasciata del prodotto. Gli assembly rilasciati al pubblico devono essere contrassegnati con un numero di versione ufficiale, che garantisce che questi problemi vengano evitati. Per altre informazioni, vedere Controllo delle versioni degli assembly.
Per diagnosticare e correggere un errore di incompatibilità
È possibile che si verifichino eccezioni di runtime o altre condizioni di errore nel codice che fanno riferimento a un altro assembly. Se non è possibile identificare un'altra causa, il problema potrebbe essere un assembly non aggiornato.
Prima di tutto, isolare e riprodurre l'eccezione o un'altra condizione di errore. Un problema che si verifica a causa di un'eccezione obsoleta deve essere riproducibile.
Controllare il timestamp di tutti gli assembly a cui si fa riferimento nell'applicazione.
Se i timestamp di qualsiasi assembly a cui si fa riferimento sono successivi al timestamp dell'ultima compilazione dell'applicazione, l'applicazione non è aggiornata. Se non è aggiornato, ricompilare l'applicazione con gli assembly più recenti e modificare il codice, se necessario.
Eseguire di nuovo l'applicazione, eseguire i passaggi che riproducono il problema e verificare che l'eccezione non si verifichi.
Esempio
Il programma seguente illustra il problema: riduce innanzitutto l'accessibilità di un metodo e quindi tenta di accedere a tale metodo in un altro assembly senza ricompilare. Compilare changeaccess.cpp
prima di tutto. Si tratta dell'assembly a cui si fa riferimento che cambierà. referencing.cpp
Compilare quindi . Dovrebbe essere compilato correttamente. Ridurre quindi l'accessibilità del metodo chiamato. Ricompilare changeaccess.cpp
con l'opzione /DCHANGE_ACCESS
del compilatore . Rende il access_me
metodo , anziché public
, in modo che non possa essere chiamato dall'esterno Test
o protected
dai suoi derivati. Senza ricompilare referencing.exe
, eseguire di nuovo l'applicazione. Si verifica un oggetto 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;
}
};
Ecco l'origine per l'assembly di riferimento:
// 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;
}
Vedi anche
Programmazione .NET con C++/CLI (Visual C++)
Interoperabilità con altri linguaggi .NET (C++/CLI)
Tipi gestiti (C++/CLI)
Direttiva #using