Types managés (C++/CLI)
Visual C++ autorise l’accès aux fonctionnalités .NET par le biais de types managés, qui fournissent une prise en charge des fonctionnalités du Common Language Runtime et sont soumises aux avantages et restrictions du runtime.
Types managés et fonction principale
Lorsque vous écrivez une application à l’aide /clr
de , les arguments de la main()
fonction ne peuvent pas être d’un type managé.
Voici un exemple de signature appropriée :
// managed_types_and_main.cpp
// compile with: /clr
int main(int, char*[], char*[]) {}
Équivalents .NET Framework aux types natifs C++
Le tableau suivant présente les mots clés pour les types Visual C++ intégrés, qui sont des alias de types prédéfinis dans l’espace de noms Système .
Type Visual C++ | Type .NET Framework |
---|---|
void |
System.Void |
bool |
System.Boolean |
signed char |
System.SByte |
unsigned char |
System.Byte |
wchar_t |
System.Char |
short et signed short |
System.Int16 |
unsigned short |
System.UInt16 |
int , signed int , long et signed long |
System.Int32 |
unsigned int et unsigned long |
System.UInt32 |
__int64 et signed __int64 |
System.Int64 |
unsigned __int64 |
System.UInt64 |
float |
System.Single |
double et long double |
System.Double |
Pour plus d’informations sur l’option du compilateur sur signed char
la valeur par défaut ou unsigned char
, consultez /J
(Type par défaut char
est unsigned
).
Problèmes de version pour les types valeur imbriqués dans les types natifs
Considérez un composant d’assembly signé (nom fort) utilisé pour générer un assembly client. Le composant contient un type valeur utilisé dans le client comme type pour un membre d’une union native, d’une classe ou d’un tableau. Si une version ultérieure du composant modifie la taille ou la disposition du type valeur, le client doit être recompilé.
Créez un fichier de clés avec sn.exe (sn -k mykey.snk
).
Exemple
L’exemple suivant est le composant.
// 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);
}
};
Cet exemple est le 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'exemple génère cette sortie :
S.i = 5
S.i = 6
S.i = 10
S.i = 11
Commentaires
Toutefois, si vous ajoutez un autre membre dans struct S
nested_value_types.cpp
(par exemple double d;
) et recompilez le composant sans recompiler le client, le résultat est une exception non gérée (de type System.IO.FileLoadException).
Comment tester l’égalité
Dans l’exemple suivant, un test d’égalité qui utilise Extensions managées pour C++ est basé sur ce que les handles font référence.
Exemple
// mcppv2_equality_test.cpp
// compile with: /clr /LD
using namespace System;
bool Test1() {
String ^ str1 = "test";
String ^ str2 = "test";
return (str1 == str2);
}
L’il de ce programme indique que la valeur de retour est implémentée à l’aide d’un appel à op_Equality
.
IL_0012: call bool [mscorlib]System.String::op_Equality(string, string)
Comment diagnostiquer et résoudre les problèmes de compatibilité d’assembly
Lorsque la version d’un assembly référencé au moment de la compilation ne correspond pas à la version de l’assembly référencé lors de l’exécution, différents problèmes peuvent se produire.
Lorsqu’un assembly est compilé, d’autres assemblys peuvent être référencés avec la #using
syntaxe. Pendant la compilation, ces assemblys sont accessibles par le compilateur. Les informations de ces assemblys sont utilisées pour prendre des décisions d’optimisation.
Toutefois, si l’assembly référencé est modifié et recompilé, recompilez également l’assembly de référencement dépendant de celui-ci. Sinon, les assemblys peuvent devenir incompatibles. Les décisions d’optimisation valides au début peuvent ne pas être correctes pour la nouvelle version de l’assembly. Diverses erreurs d’exécution peuvent se produire en raison de ces incompatibilités. Il n’existe aucune exception spécifique produite dans de tels cas. La façon dont l’échec est signalé au moment de l’exécution dépend de la nature de la modification du code qui a provoqué le problème.
Ces erreurs ne doivent pas être un problème dans votre code de production final tant que l’ensemble de l’application est reconstruite pour la version publiée de votre produit. Les assemblys publiés au public doivent être marqués avec un numéro de version officiel, ce qui garantit que ces problèmes sont évités. Pour plus d’informations, consultez Versioning des assemblys.
Pour diagnostiquer et corriger une erreur d’incompatibilité
Vous pouvez rencontrer des exceptions d’exécution ou d’autres conditions d’erreur dans le code qui fait référence à un autre assembly. Si vous ne pouvez pas identifier une autre cause, le problème peut être un assembly obsolète.
Tout d’abord, isolez et reproduisez l’exception ou une autre condition d’erreur. Un problème qui se produit en raison d’une exception obsolète doit être reproductible.
Vérifiez l’horodatage des assemblys référencés dans votre application.
Si les horodatages d’assemblys référencés sont plus tard que l’horodatage de la dernière compilation de votre application, votre application est obsolète. S’il est obsolète, recompilez votre application avec les assemblys les plus récents et modifiez votre code si nécessaire.
Réexécutez l’application, effectuez les étapes qui reproduisent le problème et vérifiez que l’exception ne se produit pas.
Exemple
Le programme suivant illustre le problème : il réduit d’abord l’accessibilité d’une méthode, puis tente d’accéder à cette méthode dans un autre assembly sans recompiler. Commencez par compiler changeaccess.cpp
. Il s’agit de l’assembly référencé qui va changer. Compilez referencing.cpp
ensuite . Elle doit être compilée avec succès. Ensuite, réduisez l’accessibilité de la méthode appelée. Recompilez changeaccess.cpp
avec l’option /DCHANGE_ACCESS
du compilateur . Il rend la access_me
méthode protected
, plutôt que public
, de sorte qu’elle ne peut pas être appelée à partir de l’extérieur Test
ou de ses dérivés. Sans recompiler referencing.exe
, réexécutez l’application. A MethodAccessException se produit.
// 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;
}
};
Voici la source de l’assembly de référencement :
// 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;
}
Voir aussi
Programmation .NET avec C++/CLI (Visual C++)
Interopérabilité avec d’autres langages .NET (C++/CLI)
Types managés (C++/CLI)
Directive #using