Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de changer d’annuaire.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer d’annuaire.
Lors de la publication de votre application en tant qu’AOT natif, le processus de génération produit toutes les structures de code et de données natives requises pour prendre en charge l’application au moment de l’exécution. Cela diffère des déploiements non natifs, qui exécutent l’application à partir de formats qui décrivent l’application en termes abstraits (un programme pour une machine virtuelle) et créent des représentations natives à la demande au moment de l’exécution.
Les représentations abstraites des parties de programme n’ont pas de mappage un-à-un à la représentation native. Par exemple, la description abstraite de la méthode générique List<T>.Add correspond à des corps de méthodes natifs en nombre potentiellement infini qui doivent être spécialisés pour l'élément spécifique T (par exemple, List<int>.Add et List<double>.Add).
Étant donné que la relation du code abstrait au code natif n’est pas un-à-un, le processus de génération doit créer une liste complète des corps de code natifs et des structures de données au moment de la génération. Il peut être difficile de créer cette liste au moment de la génération pour certaines API .NET. Si l’API est utilisée d’une manière qui n’a pas été prévue au moment de la génération, une exception est levée au moment de l’exécution.
Pour empêcher les modifications du comportement lors du déploiement en tant que kit de développement logiciel (SDK) .NET natif, le KIT DE développement logiciel (SDK) .NET fournit une analyse statique de la compatibilité AOT par le biais des « avertissements AOT ». Les avertissements AOT sont générés lorsque la build trouve du code qui peut ne pas être compatible avec AOT. Le code qui n'est pas compatible avec AOT peut entraîner des changements de comportement ou même des plantages dans une application après sa compilation en tant que Native AOT. Dans l’idéal, toutes les applications qui utilisent Native AOT ne doivent pas avoir d’avertissements AOT. S’il existe des avertissements AOT, vérifiez qu’il n’y a aucune modification de comportement en testant soigneusement votre application après l'avoir assemblée en tant que AOT native.
Exemples d’avertissements AOT
Pour la plupart du code C#, il est simple de déterminer quel code natif doit être généré. Le compilateur natif peut parcourir les corps de méthode et trouver le code natif et les structures de données accessibles. Malheureusement, certaines caractéristiques, comme la réflexion, présentent un problème important. Considérez le code suivant :
Type t = typeof(int);
while (true)
{
t = typeof(GenericType<>).MakeGenericType(t);
Console.WriteLine(Activator.CreateInstance(t));
}
struct GenericType<T> { }
Bien que le programme ci-dessus ne soit pas très utile, il représente un cas extrême qui nécessite un nombre infini de types génériques à créer lors de la génération de l’application en tant qu’AOT natif. Sans AOT natif, le programme s’exécuterait jusqu’à ce qu’il manque de mémoire. Avec l’AOT natif, nous ne pourrions même pas le construire si nous devions générer un nombre infini de types nécessaires.
Dans ce cas, la build AOT native émet l’avertissement suivant sur la ligne MakeGenericType :
AOT analysis warning IL3050: Program.<Main>$(String[]): Using member 'System.Type.MakeGenericType(Type[])' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for this instantiation might not be available at runtime.
À l'exécution, l'application générera effectivement une exception de l'appel MakeGenericType.
Réagir aux avertissements AOT
Les avertissements AOT sont destinés à donner de la prévisibilité aux builds AOT natives. La majorité des avertissements AOT concernent l’exception d’exécution possible dans les situations où le code natif n’a pas été généré pour prendre en charge le scénario. La catégorie la plus large est RequiresDynamicCodeAttribute.
NécessiteCodeDynamique
RequiresDynamicCodeAttribute est simple et large : il s’agit d’un attribut qui signifie que le membre a été annoté comme étant incompatible avec AOT. Cette annotation signifie que le membre peut utiliser la réflexion ou un autre mécanisme pour créer du code natif au moment de l’exécution. Cet attribut est utilisé lorsque le code n’est pas fondamentalement compatible avec AOT, ou que la dépendance native est trop complexe pour prédire statiquement au moment de la génération. Cela serait souvent vrai pour les méthodes qui utilisent l'API, ou d'autres technologies de génération de code à l'exécution, telles que l'émission de réflexion. Le code suivant montre un exemple.
[RequiresDynamicCode("Use 'MethodFriendlyToAot' instead")]
void MethodWithReflectionEmit() { ... }
void TestMethod()
{
// IL3050: Using method 'MethodWithReflectionEmit' which has 'RequiresDynamicCodeAttribute'
// can break functionality when AOT compiling. Use 'MethodFriendlyToAot' instead.
MethodWithReflectionEmit();
}
Il n’existe pas beaucoup de solutions de contournement pour RequiresDynamicCode. Le meilleur correctif consiste à éviter complètement d’appeler la méthode lors de la compilation en tant que AOT natif et à utiliser quelque chose d’autre compatible avec AOT. Si vous écrivez une bibliothèque et qu’il n’est pas sous votre contrôle d’appeler ou non la méthode, vous pouvez aussi ajouter RequiresDynamicCode à votre propre méthode. Cela annote votre méthode comme non compatible avec AOT. L’ajout de RequiresDynamicCode fait que tous les avertissements AOT dans la méthode annotée ne seront pas émis, mais produit un avertissement chaque fois que quelqu’un d’autre l’appelle. C’est pourquoi il est surtout utile pour les auteurs de bibliothèques de « remonter » l’avertissement vers une API publique.
Si vous pouvez en quelque sorte déterminer que l’appel est sécurisé et que tout le code natif sera disponible au moment de l’exécution, vous pouvez également supprimer l’avertissement à l’aide UnconditionalSuppressMessageAttributede . Par exemple:
[RequiresDynamicCode("Use 'MethodFriendlyToAot' instead")]
void MethodWithReflectionEmit() { ... }
[UnconditionalSuppressMessage("Aot", "IL3050:RequiresDynamicCode",
Justification = "The unfriendly method is not reachable with AOT")]
void TestMethod()
{
If (RuntimeFeature.IsDynamicCodeSupported)
MethodWithReflectionEmit(); // warning suppressed
}
UnconditionalSuppressMessage est comme SuppressMessage , mais il peut être vu par publish et d’autres outils post-build. Les directives SuppressMessage et #pragma sont présentes seulement dans la source, de sorte qu’elles ne peuvent pas être utilisées pour que les avertissements de la build ne soient pas émis.
Avertissement
Soyez prudent quand vous supprimez des avertissements AOT. L’appel peut être compatible avec AOT maintenant, mais lorsque vous mettez à jour votre code, cela peut changer et vous pouvez oublier de passer en revue toutes les suppressions.