Share via


Migrer votre application Windows 8.x vers .NET Native

.NET Native fournit une compilation statique des applications dans le Microsoft Store ou sur l’ordinateur du développeur. Cela diffère de la compilation dynamique effectuée pour les applications Windows 8.x (également appelées applications du Microsoft Store) par le compilateur juste-à-temps (JIT) ou le générateur d’images natives (Ngen.exe) sur l’appareil. Malgré les différences, .NET Native tente de maintenir la compatibilité avec .NET pour les applications Windows 8.x. Dans la plupart des cas, les éléments qui fonctionnent sur les applications .NET pour Windows 8.x fonctionnent également avec .NET Native. Toutefois, dans certains cas, vous pouvez rencontrer des changements de comportement. Ce document décrit ces différences entre les applications .NET standard pour Windows 8.x et les .NET Native dans les domaines suivants :

Différences générales au moment de l'exécution

  • Les exceptions, telles que TypeLoadException, levées par le compilateur JIT lorsqu’une application s’exécute sur le Common Language Runtime (CLR) entraînent généralement des erreurs au moment de la compilation lorsqu’elles sont traitées par .NET Native.

  • N'appelez pas la méthode GC.WaitForPendingFinalizers à partir du thread d'interface utilisateur d'une application. Cela peut entraîner un blocage sur .NET Native.

  • Ne vous fiez pas à l'ordre d'appel des constructeurs de classe statique. Dans .NET Native, l’ordre d’appel est différent de l’ordre sur le runtime standard. (Même avec le runtime standard, évitez de vous fier à l'ordre d'exécution des constructeurs de classe statique.)

  • Des boucles infinies sans appel (par exemple, while(true);) sur n'importe quel thread peuvent entraîner l'arrêt de l'application. Il en va de même dans le cas des attentes de longues durées ou infinies.

  • Certains cycles d’initialisation génériques ne lèvent pas d’exceptions dans .NET Native. Par exemple, le code suivant lève une exception TypeLoadException sur le CLR standard, Dans .NET Native, ce n’est pas le cas.

    using System;
    
    struct N<T> {}
    struct X { N<X> x; }
    
    public class Example
    {
       public static void Main()
       {
          N<int> n = new N<int>();
          X x = new X();
       }
    }
    
  • Dans certains cas, .NET Native fournit différentes implémentations de bibliothèques de classes .NET Framework. Un objet retourné par une méthode implémente toujours les membres du type retourné. Toutefois, l'implémentation de sa sauvegarde étant différente, vous ne pourrez peut-être pas effectuer un cast vers le même ensemble de types comme vous le pourriez sur d'autres plateformes .NET Framework. Par exemple, dans certains cas, vous ne pourrez peut-être pas effectuer un cast de l'objet d'interface IEnumerable<T> retourné par des méthodes telles que TypeInfo.DeclaredMembers ou TypeInfo.DeclaredProperties vers T[].

  • Le cache WinInet n’est pas activé par défaut sur .NET pour les applications Windows 8.x, mais il se trouve sur .NET Native. Cela améliore les performances, mais a des implications pour les jeux de travail. Aucune action n'est nécessaire de la part du développeur.

Différences de programmation dynamique

.NET Native des liens statiques dans le code à partir de .NET Framework pour rendre l’application de code locale pour des performances maximales. Cependant, la taille des binaires doit demeurer petite, pour que l'ensemble du .NET Framework ne soit pas sollicité. Le compilateur .NET Native résout cette limitation à l’aide d’un réducteur de dépendances qui supprime les références au code inutilisé. Toutefois, .NET Native peut ne pas conserver ou générer des informations de type et du code lorsque ces informations ne peuvent pas être déduites statiquement au moment de la compilation, mais sont récupérées dynamiquement au moment de l’exécution.

.NET Native active la réflexion et la programmation dynamique. Toutefois, tous les types ne peuvent pas être marqués à des fins de réflexion, car cela rendrait la taille de code générée trop importante (en particulier parce que la réflexion sur les API publiques dans .NET Framework est prise en charge). Le compilateur .NET Native fait des choix judicieux quant aux types qui doivent prendre en charge la réflexion, et il conserve les métadonnées et génère du code uniquement pour ces types.

Par exemple, pour la liaison de données, une application doit pouvoir mapper les noms de propriété sur les fonctions. Dans .NET pour les applications Windows 8.x, le Common Language Runtime utilise automatiquement la réflexion pour fournir cette fonctionnalité pour les types managés et les types natifs accessibles au public. Dans .NET Native, le compilateur inclut automatiquement les métadonnées pour les types auxquels vous liez des données.

Le compilateur .NET Native peut également gérer les types génériques couramment utilisés tels que List<T> et Dictionary<TKey,TValue>, qui fonctionnent sans nécessiter d’indicateurs ou de directives. Le mot clé dynamic est également pris en charge, dans certaines limites.

Notes

Vous devez tester soigneusement tous les chemins de code dynamiques lors du portage de votre application vers .NET Native.

La configuration par défaut pour .NET Native est suffisante pour la plupart des développeurs, mais certains développeurs peuvent souhaiter affiner leurs configurations à l’aide d’un fichier de directives d’exécution (.rd.xml). En outre, dans certains cas, le compilateur .NET Native ne peut pas déterminer quelles métadonnées doivent être disponibles pour la réflexion et s’appuie sur des indicateurs, en particulier dans les cas suivants :

  • Certaines constructions telles que Type.MakeGenericType et MethodInfo.MakeGenericMethod ne peuvent pas être déterminées de manière statique.

  • Comme le compilateur ne peut pas déterminer les instanciations, un type générique à réfléchir doit être spécifié par les directives runtime. Cela est nécessaire à double titre : tout le code doit être inclus, et la réflexion de types génériques peut former un cycle infini (par exemple, quand une méthode générique est appelée sur un type générique).

Notes

Les directives runtime sont définies dans un fichier de directives runtime (.rd.xml). Pour obtenir des informations générales sur l’utilisation de ce fichier, consultez la rubrique Bien démarrer. Pour plus d’informations sur les directives runtime, consultez Runtime Directives (rd.xml) Configuration File Reference.

.NET Native inclut également des outils de profilage qui aident le développeur à déterminer quels types en dehors de l’ensemble par défaut doivent prendre en charge la réflexion.

Il existe un certain nombre d’autres différences individuelles liées à la réflexion dans le comportement entre .NET pour les applications Windows 8.x et .NET Native.

Dans .NET Native :

  • La réflexion privée de types et de membres de la bibliothèque de classes .NET Framework n'est pas prise en charge. Vous pouvez, toutefois, réfléchir vos propres types et membres privés, ainsi que les types et les membres dans des bibliothèques tierces.

  • La propriété ParameterInfo.HasDefaultValue retourne correctement false pour un objet ParameterInfo qui représente une valeur de retour. Dans .NET pour les applications Windows 8.x, il retourne true. Le langage intermédiaire (IL) ne prend pas en charge cela directement, et l’interprétation est laissée à la langue.

  • Les membres publics sur les structures RuntimeFieldHandle et RuntimeMethodHandle ne sont pas pris en charge. Ces types sont pris en charge uniquement pour LINQ, les arborescences d'expression et l'initialisation de tableau statique.

  • RuntimeReflectionExtensions.GetRuntimeProperties et RuntimeReflectionExtensions.GetRuntimeEvents comprennent des membres masqués dans des classes de base et peuvent donc être remplacés sans substitutions explicites. Cela vaut également pour les autres méthodes RuntimeReflectionExtensions.GetRuntime* .

  • Type.MakeArrayType et Type.MakeByRefType n’échouez pas lorsque vous essayez de créer certaines combinaisons (par exemple, un tableau d’objets byref ).

  • Vous ne pouvez pas utiliser la réflexion pour appeler des membres qui ont des paramètres de pointeur.

  • Vous ne pouvez pas utiliser la réflexion pour obtenir ou définir un champ de pointeur.

  • Lorsque le nombre d’arguments est incorrect et que le type de l’un des arguments est incorrect, .NET Native lève un ArgumentException au lieu d’un TargetParameterCountException.

  • La sérialisation binaire des exceptions n'est généralement pas prise en charge. Ainsi, les objets non sérialisables peuvent être ajoutés au dictionnaire Exception.Data .

API et scénarios non pris en charge

Les sections suivantes répertorient les API et les scénarios non pris en charge pour le développement général, l'interopérabilité et les technologies telles que HTTPClient et Windows Communication Foundation (WCF) :

Différences de développement général

Types de valeur

  • Si vous substituez les méthodes ValueType.Equals et ValueType.GetHashCode pour un type de valeur, n'appelez pas les implémentations de classe de base. Dans .NET pour les applications Windows 8.x, ces méthodes s’appuient sur la réflexion. Au moment de la compilation, .NET Native génère une implémentation qui ne repose pas sur la réflexion du runtime. Cela signifie que si vous ne remplacez pas ces deux méthodes, elles fonctionneront comme prévu, car .NET Native génère l’implémentation au moment de la compilation. Toutefois, la substitution de ces méthodes tout en appelant l'implémentation de la classe de base entraîne une exception.

  • Les types de valeurs supérieures à 1 mégaoctet ne sont pas pris en charge.

  • Les types valeur ne peuvent pas avoir de constructeur sans paramètre dans .NET Native. (C# et Visual Basic interdisent les constructeurs sans paramètre sur les types valeur. Toutefois, ceux-ci peuvent être créés dans IL.)

Tableaux

  • Les tableaux présentant une limite inférieure différente de zéro ne sont pas pris en charge. En règle générale, ces tableaux sont créés en appelant la surcharge Array.CreateInstance(Type, Int32[], Int32[]) .

  • La création dynamique de tableaux multidimensionnels n'est pas prise en charge. Ces tableaux sont généralement créés en appelant une surcharge de la méthode Array.CreateInstance qui inclut un paramètre lengths , ou en appelant la méthode Type.MakeArrayType(Int32) .

  • Les tableaux multidimensionnels qui ont quatre dimensions ou plus ne sont pas pris en charge ; il s'agit de tableaux dont la propriété Array.Rank à une valeur supérieure ou égale à quatre. Utilisez des tableaux en escalier (tableaux de tableaux) à la place. Par exemple, array[x,y,z] n'est pas valide, contrairement à array[x][y][z] .

  • L'écart entre les tableaux multidimensionnels n'est pas pris en charge et provoque une exception InvalidCastException au moment de l'exécution.

Génériques

  • Une extension de type générique infinie entraîne une erreur du compilateur. Par exemple, la compilation de ce code échoue :

    class A<T> {}
    
    class B<T> : A<B<A<T>>>
    {}
    

Pointeurs

  • Les tableaux de pointeurs ne sont pas pris en charge.

  • Vous ne pouvez pas utiliser la réflexion pour obtenir ou définir un champ de pointeur.

Sérialisation

L'attribut KnownTypeAttribute(String) n'est pas pris en charge. Utilisez plutôt l'attribut KnownTypeAttribute(Type) .

Ressources

L'utilisation de ressources localisées avec la classe EventSource n'est pas prise en charge. La propriété EventSourceAttribute.LocalizationResources ne définit pas de ressources localisées.

Délégués

Delegate.BeginInvoke et Delegate.EndInvoke ne sont pas pris en charge.

API diverses

  • La propriété TypeInfo.GUID lève une PlatformNotSupportedException exception si un GuidAttribute attribut n’est pas appliqué au type. Le GUID est utilisé principalement pour la prise en charge de COM.

  • La DateTime.Parse méthode analyse correctement les chaînes qui contiennent des dates courtes dans .NET Native. Toutefois, il ne maintient pas la compatibilité avec certaines modifications apportées à l’analyse de date et d’heure.

  • BigInteger.ToString("E")est correctement arrondi en .NET Native. Dans certaines versions du CLR, la chaîne de résultat est tronquée et non arrondie.

Différences pour HttpClient

Dans .NET Native, la HttpClientHandler classe utilise en interne WinINet (via la HttpBaseProtocolFilter classe) au lieu des WebRequest classes et WebResponse utilisées dans les applications .NET standard pour Windows 8.x. WinINet ne prend pas en charge toutes les options de configuration prises en charge par la classe HttpClientHandler . Par conséquent :

  • Certaines des propriétés de fonctionnalité lors HttpClientHandler du retour false sur .NET Native, alors qu’elles sont retournées true dans le .NET standard pour les applications Windows 8.x.

  • Certains accesseurs de propriété get de configuration retournent toujours une valeur fixe sur .NET Native différente de la valeur configurable par défaut dans .NET pour les applications Windows 8.x.

Certaines différences de comportement supplémentaires sont décrites dans les sous-sections suivantes.

Proxy

La HttpBaseProtocolFilter classe ne prend pas en charge la configuration ou le remplacement du proxy par demande. Cela signifie que toutes les requêtes sur .NET Native utilisent le serveur proxy configuré par le système ou aucun serveur proxy, en fonction de la valeur de la HttpClientHandler.UseProxy propriété. Dans .NET pour les applications Windows 8.x, le serveur proxy est défini par la HttpClientHandler.Proxy propriété . Sur .NET Native, le fait de définir sur HttpClientHandler.Proxy une valeur autre que null lève une PlatformNotSupportedException exception. La HttpClientHandler.SupportsProxy propriété retourne false sur .NET Native, alors qu’elle retourne true dans le .NET Framework standard pour les applications Windows 8.x.

Redirection automatique

La HttpBaseProtocolFilter classe n’autorise pas la configuration du nombre maximal de redirections automatiques. La valeur de la HttpClientHandler.MaxAutomaticRedirections propriété est 50 par défaut dans les applications .NET standard pour Windows 8.x et peut être modifiée. Sur .NET Native, la valeur de cette propriété est 10, et si vous essayez de la modifier, une exception est levéePlatformNotSupportedException. La HttpClientHandler.SupportsRedirectConfiguration propriété retourne false sur .NET Native, tandis qu’elle retourne true dans .NET pour les applications Windows 8.x.

Décompression automatique

.NET pour les applications Windows 8.x vous permet de définir la propriété Deflatesur , , GZipà la HttpClientHandler.AutomaticDecompression fois Deflate et GZipou None. .NET Native prend uniquement en charge Deflate avec GZip, ou None. Si vous essayez de définir la propriété AutomaticDecompression uniquement sur Deflate ou GZip , elle est automatiquement définie à la fois sur Deflate et GZip.

Cookies

La gestion des cookies est effectuée simultanément par HttpClient et WinINet. Les cookies de CookieContainer sont combinés aux cookies du cache de cookies WinINet. La suppression d'un cookie de CookieContainer empêche HttpClient de l'envoyer, mais si le cookie a déjà été vu par WinINet et que les cookies n'ont pas été supprimés par l'utilisateur, WinInet l'envoie. Il est impossible de supprimer par programmation un cookie de WinINet à l'aide de l'API HttpClient, HttpClientHandlerou CookieContainer . Définir la propriété HttpClientHandler.UseCookies sur false entraîne uniquement l'arrêt de l'envoi des cookies par HttpClient ; WinINet peut toujours inclure ses cookies dans la demande.

Informations d'identification

Dans .NET pour les applications Windows 8.x, les HttpClientHandler.UseDefaultCredentials propriétés et HttpClientHandler.Credentials fonctionnent indépendamment. En outre, la propriété Credentials accepte tout objet qui implémente l'interface ICredentials . Dans .NET Native, si vous définissez la UseDefaultCredentials propriété sur true , la Credentials propriété devient null. En outre, la propriété Credentials peut être définie uniquement sur null, DefaultCredentialsou un objet de type NetworkCredential. L'affectation de tout autre objet ICredentials , le plus courant étant CredentialCache, à la propriété Credentials lève une PlatformNotSupportedException.

Autres fonctionnalités non prises en charge ou non configurables

Dans .NET Native :

Différences concernant l'interopérabilité

API déconseillées

Un certain nombre d'API peu utilisées pour l'interopérabilité avec du code managé ont été déconseillées. Lorsqu’elles sont utilisées avec .NET Native, ces API peuvent lever une NotImplementedException exception ou PlatformNotSupportedException ou entraîner une erreur du compilateur. Dans .NET pour les applications Windows 8.x, ces API sont marquées comme obsolètes, bien que leur appel génère un avertissement du compilateur plutôt qu’une erreur du compilateur.

Les API dépréciées pour VARIANT le marshaling sont les suivantes :

UnmanagedType.Struct est pris en charge, mais il lève une exception dans certains scénarios, par exemple lorsqu’il est utilisé avec IDispatch ou byref des variantes.

Les API dépréciées pour la prise en charge d’IDispatch sont les suivantes :

Les API dépréciées pour les événements COM classiques sont les suivantes :

Les API dépréciées dans l’interfaceSystem.Runtime.InteropServices.ICustomQueryInterface, qui ne sont pas prises en charge dans .NET Native, incluent :

D’autres fonctionnalités d’interopérabilité non prises en charge sont les suivantes :

API de marshaling rarement utilisées :

Appel de plateforme et compatibilité avec l'interopérabilité COM

La plupart des scénarios d’appel de plateforme et d’interopérabilité COM sont toujours pris en charge dans .NET Native. En particulier, toute l'interopérabilité avec les API Windows Runtime (WinRT) et tout le marshaling nécessaire pour le Windows Runtime sont pris en charge. Cela inclut la prise en charge du marshaling pour les éléments suivants :

Toutefois, .NET Native ne prend pas en charge les éléments suivants :

Utiliser la réflexion pour appeler une méthode d'appel de plateforme n'est pas pris en charge. Vous pouvez contourner cette limitation en encapsulant l'appel de méthode dans une autre méthode et en utilisant la réflexion pour appeler le wrapper.

Autres différences par rapport aux API .NET pour les applications Windows 8.x

Cette section répertorie les API restantes qui ne sont pas prises en charge dans .NET Native. Le plus grand ensemble d’API non prises en charge est celui des API Windows Communication Foundation (WCF).

DataAnnotations (System.ComponentModel.DataAnnotations)

Les types dans les System.ComponentModel.DataAnnotations espaces de noms et System.ComponentModel.DataAnnotations.Schema ne sont pas pris en charge dans .NET Native. Il s’agit notamment des types suivants présents dans .NET pour les applications Windows 8.x :

Visual Basic

Visual Basic n’est actuellement pas pris en charge dans .NET Native. Les types suivants dans les Microsoft.VisualBasic espaces de noms et Microsoft.VisualBasic.CompilerServices ne sont pas disponibles dans .NET Native :

Contexte de réflexion (espace de noms System.Reflection.Context)

La System.Reflection.Context.CustomReflectionContext classe n’est pas prise en charge dans .NET Native.

RTC (System.Net.Http.Rtc)

La System.Net.Http.RtcRequestFactory classe n’est pas prise en charge dans .NET Native.

Windows Communication Foundation (WCF) (System.ServiceModel.*)

Les types des espaces de noms System.ServiceModel.* ne sont pas pris en charge dans .NET Native. Il s’agit des types suivants :

Différences entre les sérialiseurs

Les différences suivantes concernent la sérialisation et la désérialisation avec les classes DataContractSerializer, DataContractJsonSerializeret XmlSerializer :

Différences concernant Visual Studio

Exceptions et débogage

Lorsque vous exécutez des applications compilées à l’aide de .NET Native dans le débogueur, les exceptions de première chance sont activées pour les types d’exceptions suivants :

Création d’applications

Recourez aux outils de génération x86 qui sont utilisés par défaut par Visual Studio. Nous vous déconseillons d'utiliser les outils MSBuild AMD64, qui se trouvent dans C:\Program Files (x86)\MSBuild\12.0\bin\amd64, car ils peuvent créer des problèmes de génération.

Profileurs

  • Le profileur d'UC Visual Studio et le profileur de mémoire XAML n'affichent pas Uniquement mon code correctement.

  • Le profileur de mémoire XAML n'affiche pas avec précision les données du tas managé.

  • Le profileur d'UC ne peut pas identifier correctement les modules, et affiche les noms de fonction avec préfixe.

Projets de bibliothèque de tests unitaires

L’activation de .NET Native sur une bibliothèque de tests unitaires pour un projet d’application Windows 8.x n’est pas prise en charge et entraîne l’échec de la génération du projet.

Voir aussi