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 /clrde , 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 mot clé 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.

  1. 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.

  2. Vérifiez l’horodatage des assemblys référencés dans votre application.

  3. 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.

  4. 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.cppensuite . 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_ACCESSdu 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